mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
174
gamemodes/helix/gamemode/core/derma/cl_attribute.lua
Normal file
174
gamemodes/helix/gamemode/core/derma/cl_attribute.lua
Normal file
@@ -0,0 +1,174 @@
|
||||
--[[
|
||||
| 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 gradient = ix.util.GetMaterial("vgui/gradient-u")
|
||||
local gradient2 = ix.util.GetMaterial("vgui/gradient-d")
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "color", "Color")
|
||||
AccessorFunc(PANEL, "value", "Value", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "boostValue", "Boost", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "max", "Max", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetTall(20)
|
||||
|
||||
self.add = self:Add("DImageButton")
|
||||
self.add:SetSize(16, 16)
|
||||
self.add:Dock(RIGHT)
|
||||
self.add:DockMargin(2, 2, 2, 2)
|
||||
self.add:SetImage("icon16/add.png")
|
||||
self.add.OnMousePressed = function()
|
||||
self.pressing = 1
|
||||
self:DoChange()
|
||||
self.add:SetAlpha(150)
|
||||
end
|
||||
self.add.OnMouseReleased = function()
|
||||
if (self.pressing) then
|
||||
self.pressing = nil
|
||||
self.add:SetAlpha(255)
|
||||
end
|
||||
end
|
||||
self.add.OnCursorExited = self.add.OnMouseReleased
|
||||
|
||||
self.sub = self:Add("DImageButton")
|
||||
self.sub:SetSize(16, 16)
|
||||
self.sub:Dock(LEFT)
|
||||
self.sub:DockMargin(2, 2, 2, 2)
|
||||
self.sub:SetImage("icon16/delete.png")
|
||||
self.sub.OnMousePressed = function()
|
||||
self.pressing = -1
|
||||
self:DoChange()
|
||||
self.sub:SetAlpha(150)
|
||||
end
|
||||
self.sub.OnMouseReleased = function()
|
||||
if (self.pressing) then
|
||||
self.pressing = nil
|
||||
self.sub:SetAlpha(255)
|
||||
end
|
||||
end
|
||||
self.sub.OnCursorExited = self.sub.OnMouseReleased
|
||||
|
||||
self.value = 0
|
||||
self.deltaValue = self.value
|
||||
self.max = 10
|
||||
|
||||
self.bar = self:Add("DPanel")
|
||||
self.bar:Dock(FILL)
|
||||
self.bar.Paint = function(this, w, h)
|
||||
surface.SetDrawColor(35, 35, 35, 250)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
|
||||
w, h = w - 4, h - 4
|
||||
|
||||
local value = self.deltaValue / self.max
|
||||
|
||||
if (value > 0) then
|
||||
local color = self.color and self.color or ix.config.Get("color")
|
||||
local boostedValue = self.boostValue or 0
|
||||
local add = 0
|
||||
|
||||
if (self.deltaValue != self.value) then
|
||||
add = 35
|
||||
end
|
||||
|
||||
-- your stat
|
||||
do
|
||||
if !(boostedValue < 0 and math.abs(boostedValue) > self.value) then
|
||||
surface.SetDrawColor(color.r + add, color.g + add, color.b + add, 230)
|
||||
surface.DrawRect(2, 2, w * value, h)
|
||||
|
||||
surface.SetDrawColor(255, 255, 255, 35)
|
||||
surface.SetMaterial(gradient)
|
||||
surface.DrawTexturedRect(2, 2, w * value, h)
|
||||
end
|
||||
end
|
||||
|
||||
-- boosted stat
|
||||
do
|
||||
local boostValue
|
||||
|
||||
if (boostedValue != 0) then
|
||||
if (boostedValue < 0) then
|
||||
local please = math.min(self.value, math.abs(boostedValue))
|
||||
boostValue = ((please or 0) / self.max) * (self.deltaValue / self.value)
|
||||
else
|
||||
boostValue = ((boostedValue or 0) / self.max) * (self.deltaValue / self.value)
|
||||
end
|
||||
|
||||
if (boostedValue < 0) then
|
||||
surface.SetDrawColor(200, 40, 40, 230)
|
||||
|
||||
local bWidth = math.abs(w * boostValue)
|
||||
surface.DrawRect(2 + w * value - bWidth, 2, bWidth, h)
|
||||
|
||||
surface.SetDrawColor(255, 255, 255, 35)
|
||||
surface.SetMaterial(gradient)
|
||||
surface.DrawTexturedRect(2 + w * value - bWidth, 2, bWidth, h)
|
||||
else
|
||||
surface.SetDrawColor(40, 200, 40, 230)
|
||||
surface.DrawRect(2 + w * value, 2, w * boostValue, h)
|
||||
|
||||
surface.SetDrawColor(255, 255, 255, 35)
|
||||
surface.SetMaterial(gradient)
|
||||
surface.DrawTexturedRect(2 + w * value, 2, w * boostValue, h)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
surface.SetDrawColor(255, 255, 255, 5)
|
||||
surface.SetMaterial(gradient2)
|
||||
surface.DrawTexturedRect(2, 2, w, h)
|
||||
end
|
||||
|
||||
self.label = self.bar:Add("DLabel")
|
||||
self.label:Dock(FILL)
|
||||
self.label:SetExpensiveShadow(1, Color(0, 0, 60))
|
||||
self.label:SetContentAlignment(5)
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
if (self.pressing) then
|
||||
if ((self.nextPress or 0) < CurTime()) then
|
||||
self:DoChange()
|
||||
end
|
||||
end
|
||||
|
||||
self.deltaValue = math.Approach(self.deltaValue, self.value, FrameTime() * 15)
|
||||
end
|
||||
|
||||
function PANEL:DoChange()
|
||||
if ((self.value == 0 and self.pressing == -1) or (self.value == self.max and self.pressing == 1)) then
|
||||
return
|
||||
end
|
||||
|
||||
self.nextPress = CurTime() + 0.2
|
||||
|
||||
if (self:OnChanged(self.pressing) != false) then
|
||||
self.value = math.Clamp(self.value + self.pressing, 0, self.max)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnChanged(difference)
|
||||
end
|
||||
|
||||
function PANEL:SetText(text)
|
||||
self.label:SetText(text)
|
||||
end
|
||||
|
||||
function PANEL:SetReadOnly()
|
||||
self.sub:Remove()
|
||||
self.add:Remove()
|
||||
end
|
||||
|
||||
vgui.Register("ixAttributeBar", PANEL, "DPanel")
|
||||
207
gamemodes/helix/gamemode/core/derma/cl_bar.lua
Normal file
207
gamemodes/helix/gamemode/core/derma/cl_bar.lua
Normal file
@@ -0,0 +1,207 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- bar manager
|
||||
-- this manages positions for bar panels
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSize(ScrW() * 0.35, ScrH())
|
||||
self:SetPos(4, 4)
|
||||
self:ParentToHUD()
|
||||
|
||||
self.bars = {}
|
||||
self.padding = 2
|
||||
|
||||
-- add bars that were registered before manager creation
|
||||
for _, v in ipairs(ix.bar.list) do
|
||||
v.panel = self:AddBar(v.index, v.color, v.priority)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:GetAll()
|
||||
return self.bars
|
||||
end
|
||||
|
||||
function PANEL:Clear()
|
||||
for k, v in ipairs(self.bars) do
|
||||
v:Remove()
|
||||
|
||||
table.remove(self.bars, k)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:AddBar(index, color, priority)
|
||||
local panel = self:Add("ixInfoBar")
|
||||
panel:SetSize(self:GetWide(), BAR_HEIGHT)
|
||||
panel:SetVisible(false)
|
||||
panel:SetID(index)
|
||||
panel:SetColor(color)
|
||||
panel:SetPriority(priority)
|
||||
|
||||
self.bars[#self.bars + 1] = panel
|
||||
self:Sort()
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
function PANEL:RemoveBar(panel)
|
||||
local toRemove
|
||||
|
||||
for k, v in ipairs(self.bars) do
|
||||
if (v == panel) then
|
||||
toRemove = k
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if (toRemove) then
|
||||
table.remove(self.bars, toRemove)
|
||||
|
||||
-- Decrease index value for the next bars
|
||||
for i = toRemove, #self.bars do
|
||||
ix.bar.list[i].index = i
|
||||
self.bars[i]:SetID(i)
|
||||
end
|
||||
end
|
||||
|
||||
panel:Remove()
|
||||
self:Sort()
|
||||
end
|
||||
|
||||
-- sort bars by priority
|
||||
function PANEL:Sort()
|
||||
table.sort(self.bars, function(a, b)
|
||||
return a:GetPriority() < b:GetPriority()
|
||||
end)
|
||||
end
|
||||
|
||||
-- update target Y positions
|
||||
function PANEL:Organize()
|
||||
local currentY = 0
|
||||
|
||||
for _, v in ipairs(self.bars) do
|
||||
if (!v:IsVisible()) then
|
||||
continue
|
||||
end
|
||||
|
||||
v:SetPos(0, currentY)
|
||||
|
||||
currentY = currentY + self.padding + v:GetTall()
|
||||
end
|
||||
|
||||
self:SetSize(self:GetWide(), currentY)
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
local menu = (IsValid(ix.gui.characterMenu) and !ix.gui.characterMenu:IsClosing()) and ix.gui.characterMenu
|
||||
or IsValid(ix.gui.menu) and ix.gui.menu
|
||||
local fraction = menu and 1 - menu.currentAlpha / 255 or 1
|
||||
|
||||
self:SetAlpha(255 * fraction)
|
||||
|
||||
-- don't update bars when not visible
|
||||
if (fraction == 0) then
|
||||
return
|
||||
end
|
||||
|
||||
local curTime = CurTime()
|
||||
local bShouldHide = hook.Run("ShouldHideBars")
|
||||
local bAlwaysShow = ix.option.Get("alwaysShowBars", false)
|
||||
|
||||
for _, v in ipairs(self.bars) do
|
||||
local info = ix.bar.list[v:GetID()]
|
||||
local realValue, barText = info.GetValue()
|
||||
|
||||
if (bShouldHide or realValue == false) then
|
||||
v:SetVisible(false)
|
||||
continue
|
||||
end
|
||||
|
||||
if (v:GetDelta() != realValue) then
|
||||
v:SetLifetime(curTime + 5)
|
||||
end
|
||||
|
||||
if (v:GetLifetime() < curTime and !info.visible and !bAlwaysShow and !hook.Run("ShouldBarDraw", info)) then
|
||||
v:SetVisible(false)
|
||||
continue
|
||||
end
|
||||
|
||||
v:SetVisible(true)
|
||||
v:SetValue(realValue)
|
||||
v:SetText(isstring(barText) and barText or "")
|
||||
end
|
||||
|
||||
self:Organize()
|
||||
end
|
||||
|
||||
function PANEL:OnRemove()
|
||||
self:Clear()
|
||||
end
|
||||
|
||||
vgui.Register("ixInfoBarManager", PANEL, "Panel")
|
||||
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "index", "ID", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "color", "Color")
|
||||
AccessorFunc(PANEL, "priority", "Priority", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "value", "Value", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "delta", "Delta", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "lifetime", "Lifetime", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self.value = 0
|
||||
self.delta = 0
|
||||
self.lifetime = 0
|
||||
|
||||
self.bar = self:Add("DPanel")
|
||||
self.bar:SetPaintedManually(true)
|
||||
self.bar:Dock(FILL)
|
||||
self.bar:DockMargin(2, 2, 2, 2)
|
||||
self.bar.Paint = function(this, width, height)
|
||||
width = width * math.min(self.delta, 1)
|
||||
|
||||
derma.SkinFunc("PaintInfoBar", self, width, height, self.color)
|
||||
end
|
||||
|
||||
self.label = self:Add("DLabel")
|
||||
self.label:SetFont("ixSmallFont")
|
||||
self.label:SetContentAlignment(5)
|
||||
self.label:SetText("")
|
||||
self.label:SetTextColor(Color(240, 240, 240))
|
||||
self.label:SetExpensiveShadow(2, Color(20, 20, 20))
|
||||
self.label:SetPaintedManually(true)
|
||||
self.label:SizeToContents()
|
||||
self.label:Dock(FILL)
|
||||
end
|
||||
|
||||
function PANEL:SetText(text)
|
||||
self.label:SetText(text)
|
||||
self.label:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
self.delta = math.Approach(self.delta, self.value, FrameTime())
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("PaintInfoBarBackground", self, width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixInfoBar", PANEL, "Panel")
|
||||
|
||||
if (IsValid(ix.gui.bars)) then
|
||||
ix.gui.bars:Remove()
|
||||
ix.gui.bars = vgui.Create("ixInfoBarManager")
|
||||
end
|
||||
513
gamemodes/helix/gamemode/core/derma/cl_business.lua
Normal file
513
gamemodes/helix/gamemode/core/derma/cl_business.lua
Normal file
@@ -0,0 +1,513 @@
|
||||
--[[
|
||||
| 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 = {}
|
||||
|
||||
function PANEL:Init()
|
||||
-- being relative.
|
||||
local size = 120
|
||||
self:SetSize(size, size * 1.4)
|
||||
end
|
||||
|
||||
function PANEL:SetItem(itemTable)
|
||||
self.itemName = L(itemTable.name):lower()
|
||||
|
||||
self.price = self:Add("DLabel")
|
||||
self.price:Dock(BOTTOM)
|
||||
self.price:SetText(itemTable.price and ix.currency.Get(itemTable.price) or L"free":utf8upper())
|
||||
self.price:SetContentAlignment(5)
|
||||
self.price:SetTextColor(color_white)
|
||||
self.price:SetFont("ixSmallFont")
|
||||
self.price:SetExpensiveShadow(1, Color(0, 0, 0, 200))
|
||||
|
||||
self.name = self:Add("DLabel")
|
||||
self.name:Dock(TOP)
|
||||
self.name:SetText(itemTable.GetName and itemTable:GetName() or L(itemTable.name))
|
||||
self.name:SetContentAlignment(5)
|
||||
self.name:SetTextColor(color_white)
|
||||
self.name:SetFont("ixSmallFont")
|
||||
self.name:SetExpensiveShadow(1, Color(0, 0, 0, 200))
|
||||
self.name.Paint = function(this, w, h)
|
||||
surface.SetDrawColor(0, 0, 0, 75)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
end
|
||||
|
||||
self.icon = self:Add("SpawnIcon")
|
||||
self.icon:SetZPos(1)
|
||||
self.icon:SetSize(self:GetWide(), self:GetWide())
|
||||
self.icon:Dock(FILL)
|
||||
self.icon:DockMargin(5, 5, 5, 10)
|
||||
self.icon:InvalidateLayout(true)
|
||||
self.icon:SetModel(itemTable:GetModel(), itemTable:GetSkin())
|
||||
self.icon:SetHelixTooltip(function(tooltip)
|
||||
ix.hud.PopulateItemTooltip(tooltip, itemTable)
|
||||
end)
|
||||
self.icon.itemTable = itemTable
|
||||
self.icon.DoClick = function(this)
|
||||
if (IsValid(ix.gui.checkout)) then
|
||||
return
|
||||
end
|
||||
|
||||
local parent = ix.gui.business
|
||||
local bAdded = parent:BuyItem(itemTable.uniqueID)
|
||||
|
||||
if (bAdded) then
|
||||
surface.PlaySound("buttons/button14.wav")
|
||||
end
|
||||
end
|
||||
self.icon.PaintOver = function(this)
|
||||
if (itemTable and itemTable.PaintOver) then
|
||||
local w, h = this:GetSize()
|
||||
|
||||
itemTable.PaintOver(this, itemTable, w, h)
|
||||
end
|
||||
end
|
||||
|
||||
if ((itemTable.iconCam and !ICON_RENDER_QUEUE[itemTable.uniqueID]) or itemTable.forceRender) then
|
||||
local iconCam = itemTable.iconCam
|
||||
iconCam = {
|
||||
cam_pos = iconCam.pos,
|
||||
cam_fov = iconCam.fov,
|
||||
cam_ang = iconCam.ang,
|
||||
}
|
||||
ICON_RENDER_QUEUE[itemTable.uniqueID] = true
|
||||
|
||||
self.icon:RebuildSpawnIconEx(
|
||||
iconCam
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixBusinessItem", PANEL, "DPanel")
|
||||
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
ix.gui.business = self
|
||||
|
||||
self:SetSize(self:GetParent():GetSize())
|
||||
|
||||
self.categories = self:Add("DScrollPanel")
|
||||
self.categories:Dock(LEFT)
|
||||
self.categories:SetWide(260)
|
||||
self.categories.Paint = function(this, w, h)
|
||||
surface.SetDrawColor(0, 0, 0, 150)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
end
|
||||
self.categories:DockPadding(5, 5, 5, 5)
|
||||
self.categories:DockMargin(0, 46, 0, 0)
|
||||
self.categoryPanels = {}
|
||||
|
||||
self.scroll = self:Add("DScrollPanel")
|
||||
self.scroll:Dock(FILL)
|
||||
|
||||
self.search = self:Add("DTextEntry")
|
||||
self.search:Dock(TOP)
|
||||
self.search:SetTall(36)
|
||||
self.search:SetFont("ixMediumFont")
|
||||
self.search:DockMargin(10 + self:GetWide() * 0.35, 0, 5, 5)
|
||||
self.search.OnTextChanged = function(this)
|
||||
local text = self.search:GetText():lower()
|
||||
|
||||
if (self.selected) then
|
||||
self:LoadItems(self.selected.category, text:find("%S") and text or nil)
|
||||
self.scroll:InvalidateLayout()
|
||||
end
|
||||
end
|
||||
self.search.PaintOver = function(this, cw, ch)
|
||||
if (self.search:GetValue() == "" and !self.search:HasFocus()) then
|
||||
ix.util.DrawText("V", 10, ch/2 - 1, color_black, 3, 1, "ixIconsSmall")
|
||||
end
|
||||
end
|
||||
|
||||
self.itemList = self.scroll:Add("DIconLayout")
|
||||
self.itemList:Dock(TOP)
|
||||
self.itemList:DockMargin(10, 1, 5, 5)
|
||||
self.itemList:SetSpaceX(10)
|
||||
self.itemList:SetSpaceY(10)
|
||||
self.itemList:SetMinimumSize(128, 400)
|
||||
|
||||
self.checkout = self:Add("DButton")
|
||||
self.checkout:Dock(BOTTOM)
|
||||
self.checkout:SetTextColor(color_white)
|
||||
self.checkout:SetTall(36)
|
||||
self.checkout:SetFont("ixMediumFont")
|
||||
self.checkout:DockMargin(10, 10, 0, 0)
|
||||
self.checkout:SetExpensiveShadow(1, Color(0, 0, 0, 150))
|
||||
self.checkout:SetText(L("checkout", 0))
|
||||
self.checkout.DoClick = function()
|
||||
if (!IsValid(ix.gui.checkout) and self:GetCartCount() > 0) then
|
||||
vgui.Create("ixBusinessCheckout"):SetCart(self.cart)
|
||||
end
|
||||
end
|
||||
|
||||
self.cart = {}
|
||||
|
||||
local dark = Color(0, 0, 0, 50)
|
||||
local first = true
|
||||
|
||||
for k, v in pairs(ix.item.list) do
|
||||
if (hook.Run("CanPlayerUseBusiness", LocalPlayer(), k) == false) then
|
||||
continue
|
||||
end
|
||||
|
||||
if (!self.categoryPanels[L(v.category)]) then
|
||||
self.categoryPanels[L(v.category)] = v.category
|
||||
end
|
||||
end
|
||||
|
||||
for category, realName in SortedPairs(self.categoryPanels) do
|
||||
local button = self.categories:Add("DButton")
|
||||
button:SetTall(36)
|
||||
button:SetText(category)
|
||||
button:Dock(TOP)
|
||||
button:SetTextColor(color_white)
|
||||
button:DockMargin(5, 5, 5, 0)
|
||||
button:SetFont("ixMediumFont")
|
||||
button:SetExpensiveShadow(1, Color(0, 0, 0, 150))
|
||||
button.Paint = function(this, w, h)
|
||||
surface.SetDrawColor(self.selected == this and ix.config.Get("color") or dark)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
|
||||
surface.SetDrawColor(0, 0, 0, 50)
|
||||
surface.DrawOutlinedRect(0, 0, w, h)
|
||||
end
|
||||
button.DoClick = function(this)
|
||||
if (self.selected != this) then
|
||||
self.selected = this
|
||||
self:LoadItems(realName)
|
||||
timer.Simple(0.01, function()
|
||||
self.scroll:InvalidateLayout()
|
||||
end)
|
||||
end
|
||||
end
|
||||
button.category = realName
|
||||
|
||||
if (first) then
|
||||
self.selected = button
|
||||
first = false
|
||||
end
|
||||
|
||||
self.categoryPanels[realName] = button
|
||||
end
|
||||
|
||||
if (self.selected) then
|
||||
self:LoadItems(self.selected.category)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:GetCartCount()
|
||||
local count = 0
|
||||
|
||||
for _, v in pairs(self.cart) do
|
||||
count = count + v
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
function PANEL:BuyItem(uniqueID)
|
||||
local currentCount = self.cart[uniqueID] or 0
|
||||
|
||||
if (currentCount >= 10) then
|
||||
return false
|
||||
end
|
||||
|
||||
self.cart[uniqueID] = currentCount + 1
|
||||
self.checkout:SetText(L("checkout", self:GetCartCount()))
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function PANEL:LoadItems(category, search)
|
||||
category = category or "misc"
|
||||
local items = ix.item.list
|
||||
|
||||
self.itemList:Clear()
|
||||
self.itemList:InvalidateLayout(true)
|
||||
|
||||
for uniqueID, itemTable in SortedPairsByMemberValue(items, "name") do
|
||||
if (hook.Run("CanPlayerUseBusiness", LocalPlayer(), uniqueID) == false) then
|
||||
continue
|
||||
end
|
||||
|
||||
if (itemTable.category == category) then
|
||||
if (search and search != "" and !L(itemTable.name):lower():find(search, 1, true)) then
|
||||
continue
|
||||
end
|
||||
|
||||
self.itemList:Add("ixBusinessItem"):SetItem(itemTable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetPage()
|
||||
end
|
||||
|
||||
function PANEL:GetPageItems()
|
||||
end
|
||||
|
||||
vgui.Register("ixBusiness", PANEL, "EditablePanel")
|
||||
|
||||
DEFINE_BASECLASS("DFrame")
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
if (IsValid(ix.gui.checkout)) then
|
||||
ix.gui.checkout:Remove()
|
||||
end
|
||||
|
||||
ix.gui.checkout = self
|
||||
|
||||
self:SetTitle(L("checkout", 0))
|
||||
self:SetSize(ScrW() / 4 > 200 and ScrW() / 4 or ScrW() / 2, ScrH() / 2 > 300 and ScrH() / 2 or ScrH())
|
||||
self:MakePopup()
|
||||
self:Center()
|
||||
self:SetBackgroundBlur(true)
|
||||
self:SetSizable(true)
|
||||
|
||||
self.items = self:Add("DScrollPanel")
|
||||
self.items:Dock(FILL)
|
||||
self.items.Paint = function(this, w, h)
|
||||
surface.SetDrawColor(0, 0, 0, 100)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
end
|
||||
self.items:DockMargin(0, 0, 0, 4)
|
||||
|
||||
self.buy = self:Add("DButton")
|
||||
self.buy:Dock(BOTTOM)
|
||||
self.buy:SetText(L"purchase")
|
||||
self.buy:SetTextColor(color_white)
|
||||
self.buy.DoClick = function(this)
|
||||
if ((this.nextClick or 0) < CurTime()) then
|
||||
this.nextClick = CurTime() + 0.5
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
if (self.preventBuy) then
|
||||
self.finalGlow:SetText(self.final:GetText())
|
||||
self.finalGlow:SetAlpha(255)
|
||||
self.finalGlow:AlphaTo(0, 0.5)
|
||||
|
||||
return surface.PlaySound("buttons/button11.wav")
|
||||
end
|
||||
|
||||
net.Start("ixBusinessBuy")
|
||||
net.WriteUInt(table.Count(self.itemData), 8)
|
||||
|
||||
for k, v in pairs(self.itemData) do
|
||||
net.WriteString(k)
|
||||
net.WriteUInt(v, 8)
|
||||
end
|
||||
|
||||
net.SendToServer()
|
||||
|
||||
self.itemData = {}
|
||||
self.items:Remove()
|
||||
self.data:Remove()
|
||||
self.buy:Remove()
|
||||
self:ShowCloseButton(false)
|
||||
|
||||
if (IsValid(ix.gui.business)) then
|
||||
ix.gui.business.cart = {}
|
||||
ix.gui.business.checkout:SetText(L("checkout", 0))
|
||||
end
|
||||
|
||||
self.text = self:Add("DLabel")
|
||||
self.text:Dock(FILL)
|
||||
self.text:SetContentAlignment(5)
|
||||
self.text:SetTextColor(color_white)
|
||||
self.text:SetText(L"purchasing")
|
||||
self.text:SetFont("ixMediumFont")
|
||||
|
||||
net.Receive("ixBusinessResponse", function()
|
||||
if (IsValid(self)) then
|
||||
self.text:SetText(L"buyGood")
|
||||
self.done = true
|
||||
self:ShowCloseButton(true)
|
||||
|
||||
surface.PlaySound("buttons/button3.wav")
|
||||
end
|
||||
end)
|
||||
|
||||
timer.Simple(4, function()
|
||||
if (IsValid(self) and !self.done) then
|
||||
self.text:SetText(L"buyFailed")
|
||||
self:ShowCloseButton(true)
|
||||
|
||||
surface.PlaySound("buttons/button11.wav")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
self.data = self:Add("DPanel")
|
||||
self.data:Dock(BOTTOM)
|
||||
self.data:SetTall(64)
|
||||
self.data:DockMargin(0, 0, 0, 4)
|
||||
|
||||
self.current = self.data:Add("DLabel")
|
||||
self.current:SetFont("ixSmallFont")
|
||||
self.current:SetContentAlignment(6)
|
||||
self.current:SetTextColor(color_white)
|
||||
self.current:Dock(TOP)
|
||||
self.current:SetTextInset(4, 0)
|
||||
|
||||
self.total = self.data:Add("DLabel")
|
||||
self.total:SetFont("ixSmallFont")
|
||||
self.total:SetContentAlignment(6)
|
||||
self.total:SetTextColor(color_white)
|
||||
self.total:Dock(TOP)
|
||||
self.total:SetTextInset(4, 0)
|
||||
|
||||
local line = self.data:Add("DPanel")
|
||||
line:SetTall(1)
|
||||
line:DockMargin(128, 0, 4, 0)
|
||||
line:Dock(TOP)
|
||||
line.Paint = function(this, w, h)
|
||||
surface.SetDrawColor(255, 255, 255, 150)
|
||||
surface.DrawLine(0, 0, w, 0)
|
||||
end
|
||||
|
||||
self.final = self.data:Add("DLabel")
|
||||
self.final:SetFont("ixSmallFont")
|
||||
self.final:SetContentAlignment(6)
|
||||
self.final:SetTextColor(color_white)
|
||||
self.final:Dock(TOP)
|
||||
self.final:SetTextInset(4, 0)
|
||||
|
||||
self.finalGlow = self.final:Add("DLabel")
|
||||
self.finalGlow:Dock(FILL)
|
||||
self.finalGlow:SetFont("ixSmallFont")
|
||||
self.finalGlow:SetTextColor(color_white)
|
||||
self.finalGlow:SetContentAlignment(6)
|
||||
self.finalGlow:SetAlpha(0)
|
||||
self.finalGlow:SetTextInset(4, 0)
|
||||
|
||||
self:SetFocusTopLevel(true)
|
||||
self.itemData = {}
|
||||
self:OnQuantityChanged()
|
||||
end
|
||||
|
||||
function PANEL:OnQuantityChanged()
|
||||
local price = 0
|
||||
local money = LocalPlayer():GetCharacter():GetMoney()
|
||||
local valid = 0
|
||||
|
||||
for k, v in pairs(self.itemData) do
|
||||
local itemTable = ix.item.list[k]
|
||||
|
||||
if (itemTable and v > 0) then
|
||||
valid = valid + 1
|
||||
price = price + (v * (itemTable.price or 0))
|
||||
end
|
||||
end
|
||||
|
||||
self.current:SetText(L"currentMoney" .. ix.currency.Get(money))
|
||||
self.total:SetText("- " .. ix.currency.Get(price))
|
||||
self.final:SetText(L"moneyLeft" .. ix.currency.Get(money - price))
|
||||
self.final:SetTextColor((money - price) >= 0 and Color(46, 204, 113) or Color(217, 30, 24))
|
||||
|
||||
self.preventBuy = (money - price) < 0 or valid == 0
|
||||
|
||||
if (IsValid(ix.gui.business)) then
|
||||
ix.gui.business.checkout:SetText(L("checkout", ix.gui.business:GetCartCount()))
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetCart(items)
|
||||
self.itemData = items
|
||||
|
||||
for k, v in SortedPairs(items) do
|
||||
local itemTable = ix.item.list[k]
|
||||
|
||||
if (itemTable) then
|
||||
local slot = self.items:Add("DPanel")
|
||||
slot:SetTall(36)
|
||||
slot:Dock(TOP)
|
||||
slot:DockMargin(5, 5, 5, 0)
|
||||
|
||||
slot.icon = slot:Add("SpawnIcon")
|
||||
slot.icon:SetPos(2, 2)
|
||||
slot.icon:SetSize(32, 32)
|
||||
slot.icon:SetModel(itemTable:GetModel())
|
||||
slot.icon:SetTooltip()
|
||||
|
||||
slot.name = slot:Add("DLabel")
|
||||
slot.name:SetPos(40, 2)
|
||||
slot.name:SetFont("ixChatFont")
|
||||
slot.name:SetText(string.format(
|
||||
"%s (%s)",
|
||||
L(itemTable.GetName and itemTable:GetName() or L(itemTable.name)),
|
||||
itemTable.price and ix.currency.Get(itemTable.price) or L"free":utf8upper()
|
||||
))
|
||||
slot.name:SetTextColor(color_white)
|
||||
slot.name:SizeToContents()
|
||||
slot.name:DockMargin(40, 0, 0, 0)
|
||||
slot.name:Dock(FILL)
|
||||
|
||||
slot.quantity = slot:Add("DTextEntry")
|
||||
slot.quantity:SetSize(32, 32)
|
||||
slot.quantity:Dock(RIGHT)
|
||||
slot.quantity:DockMargin(4, 4, 4, 4)
|
||||
slot.quantity:SetContentAlignment(5)
|
||||
slot.quantity:SetNumeric(true)
|
||||
slot.quantity:SetText(v)
|
||||
slot.quantity:SetFont("ixChatFont")
|
||||
slot.quantity.OnTextChanged = function(this)
|
||||
local value = tonumber(this:GetValue())
|
||||
|
||||
if (!value) then
|
||||
this:SetValue(1)
|
||||
return
|
||||
end
|
||||
|
||||
value = math.Clamp(math.Round(value), 0, 10)
|
||||
|
||||
if (value == 0) then
|
||||
items[k] = nil
|
||||
|
||||
slot:Remove()
|
||||
else
|
||||
items[k] = value
|
||||
end
|
||||
|
||||
self:OnQuantityChanged()
|
||||
end
|
||||
slot.quantity.OnLoseFocus = function(this)
|
||||
local value = math.Clamp(tonumber(this:GetValue()) or 1, 0, 10)
|
||||
this:SetText(value)
|
||||
end
|
||||
else
|
||||
items[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
self:OnQuantityChanged()
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
if (!self:HasFocus()) then
|
||||
self:MakePopup()
|
||||
end
|
||||
|
||||
BaseClass.Think(self)
|
||||
end
|
||||
|
||||
vgui.Register("ixBusinessCheckout", PANEL, "DFrame")
|
||||
|
||||
hook.Add("CreateMenuButtons", "ixBusiness", function(tabs)
|
||||
if (hook.Run("BuildBusinessMenu") != false) then
|
||||
tabs["business"] = function(container)
|
||||
container:Add("ixBusiness")
|
||||
end
|
||||
end
|
||||
end)
|
||||
551
gamemodes/helix/gamemode/core/derma/cl_character.lua
Normal file
551
gamemodes/helix/gamemode/core/derma/cl_character.lua
Normal file
@@ -0,0 +1,551 @@
|
||||
--[[
|
||||
| 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 gradient = surface.GetTextureID("vgui/gradient-d")
|
||||
local audioFadeInTime = 2
|
||||
local animationTime = 0.5
|
||||
local matrixZScale = Vector(1, 1, 0.0001)
|
||||
|
||||
-- character menu panel
|
||||
DEFINE_BASECLASS("ixSubpanelParent")
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSize(self:GetParent():GetSize())
|
||||
self:SetPos(0, 0)
|
||||
|
||||
self.childPanels = {}
|
||||
self.subpanels = {}
|
||||
self.activeSubpanel = ""
|
||||
|
||||
self.currentDimAmount = 0
|
||||
self.currentY = 0
|
||||
self.currentScale = 1
|
||||
self.currentAlpha = 255
|
||||
self.targetDimAmount = 255
|
||||
self.targetScale = 0.9
|
||||
end
|
||||
|
||||
function PANEL:Dim(length, callback)
|
||||
length = length or animationTime
|
||||
self.currentDimAmount = 0
|
||||
|
||||
self:CreateAnimation(length, {
|
||||
target = {
|
||||
currentDimAmount = self.targetDimAmount,
|
||||
currentScale = self.targetScale
|
||||
},
|
||||
easing = "outCubic",
|
||||
OnComplete = callback
|
||||
})
|
||||
|
||||
self:OnDim()
|
||||
end
|
||||
|
||||
function PANEL:Undim(length, callback)
|
||||
length = length or animationTime
|
||||
self.currentDimAmount = self.targetDimAmount
|
||||
|
||||
self:CreateAnimation(length, {
|
||||
target = {
|
||||
currentDimAmount = 0,
|
||||
currentScale = 1
|
||||
},
|
||||
easing = "outCubic",
|
||||
OnComplete = callback
|
||||
})
|
||||
|
||||
self:OnUndim()
|
||||
end
|
||||
|
||||
function PANEL:OnDim()
|
||||
end
|
||||
|
||||
function PANEL:OnUndim()
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
local amount = self.currentDimAmount
|
||||
local bShouldScale = self.currentScale != 1
|
||||
local matrix
|
||||
|
||||
-- draw child panels with scaling if needed
|
||||
if (bShouldScale) then
|
||||
matrix = Matrix()
|
||||
matrix:Scale(matrixZScale * self.currentScale)
|
||||
matrix:Translate(Vector(
|
||||
ScrW() * 0.5 - (ScrW() * self.currentScale * 0.5),
|
||||
ScrH() * 0.5 - (ScrH() * self.currentScale * 0.5),
|
||||
1
|
||||
))
|
||||
|
||||
cam.PushModelMatrix(matrix)
|
||||
self.currentMatrix = matrix
|
||||
end
|
||||
|
||||
BaseClass.Paint(self, width, height)
|
||||
|
||||
if (bShouldScale) then
|
||||
cam.PopModelMatrix()
|
||||
self.currentMatrix = nil
|
||||
end
|
||||
|
||||
if (amount > 0) then
|
||||
local color = Color(0, 0, 0, amount)
|
||||
|
||||
surface.SetDrawColor(color)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixCharMenuPanel", PANEL, "ixSubpanelParent")
|
||||
|
||||
-- character menu main button list
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
local parent = self:GetParent()
|
||||
self:SetSize(parent:GetWide() * 0.25, parent:GetTall())
|
||||
|
||||
self:GetVBar():SetWide(0)
|
||||
self:GetVBar():SetVisible(false)
|
||||
end
|
||||
|
||||
function PANEL:Add(name)
|
||||
local panel = vgui.Create(name, self)
|
||||
panel:Dock(TOP)
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
self:GetCanvas():InvalidateLayout(true)
|
||||
|
||||
-- if the canvas has extra space, forcefully dock to the bottom so it doesn't anchor to the top
|
||||
if (self:GetTall() > self:GetCanvas():GetTall()) then
|
||||
self:GetCanvas():Dock(BOTTOM)
|
||||
else
|
||||
self:GetCanvas():Dock(NODOCK)
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixCharMenuButtonList", PANEL, "DScrollPanel")
|
||||
|
||||
-- main character menu panel
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "bUsingCharacter", "UsingCharacter", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
local parent = self:GetParent()
|
||||
local padding = self:GetPadding()
|
||||
local halfWidth = ScrW() * 0.5
|
||||
local halfPadding = padding * 0.5
|
||||
local bHasCharacter = #ix.characters > 0
|
||||
|
||||
self.bUsingCharacter = LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()
|
||||
self:DockPadding(padding, padding, padding, padding)
|
||||
|
||||
local infoLabel = self:Add("DLabel")
|
||||
infoLabel:SetTextColor(Color(255, 255, 255, 25))
|
||||
infoLabel:SetFont("ixMenuMiniFont")
|
||||
infoLabel:SetText(L("helix") .. " " .. GAMEMODE.Version)
|
||||
infoLabel:SizeToContents()
|
||||
infoLabel:SetPos(ScrW() - infoLabel:GetWide() - 4, ScrH() - infoLabel:GetTall() - 4)
|
||||
|
||||
local logoPanel = self:Add("Panel")
|
||||
logoPanel:SetSize(ScrW(), ScrH() * 0.25)
|
||||
logoPanel:SetPos(0, ScrH() * 0.25)
|
||||
logoPanel.Paint = function(panel, width, height)
|
||||
local matrix = self.currentMatrix
|
||||
|
||||
-- don't scale the background because it fucks the blur
|
||||
if (matrix) then
|
||||
cam.PopModelMatrix()
|
||||
end
|
||||
|
||||
local newHeight = Lerp(1 - (self.currentDimAmount / 255), 0, height)
|
||||
local y = height * 0.5 - newHeight * 0.5
|
||||
local _, screenY = panel:LocalToScreen(0, 0)
|
||||
screenY = screenY + y
|
||||
|
||||
render.SetScissorRect(0, screenY, width, screenY + newHeight, true)
|
||||
ix.util.DrawBlur(panel, 15, nil, 200)
|
||||
|
||||
-- background dim
|
||||
surface.SetDrawColor(0, 0, 0, 100)
|
||||
surface.DrawRect(0, y, width, newHeight)
|
||||
|
||||
-- border lines
|
||||
surface.SetDrawColor(ix.config.Get("color") or color_white)
|
||||
surface.DrawRect(0, y, width, 1)
|
||||
surface.DrawRect(0, y + newHeight - 1, width, 1)
|
||||
|
||||
if (matrix) then
|
||||
cam.PushModelMatrix(matrix)
|
||||
end
|
||||
|
||||
for _, v in ipairs(panel:GetChildren()) do
|
||||
v:PaintManual()
|
||||
end
|
||||
|
||||
render.SetScissorRect(0, 0, 0, 0, false)
|
||||
end
|
||||
|
||||
-- draw schema logo material instead of text if available
|
||||
local logo = Schema.logo and ix.util.GetMaterial(Schema.logo)
|
||||
|
||||
if (logo and !logo:IsError()) then
|
||||
local logoImage = logoPanel:Add("DImage")
|
||||
logoImage:SetMaterial(logo)
|
||||
logoImage:SetSize(halfWidth, halfWidth * logo:Height() / logo:Width())
|
||||
logoImage:SetPos(halfWidth - logoImage:GetWide() * 0.5, halfPadding)
|
||||
logoImage:SetPaintedManually(true)
|
||||
|
||||
logoPanel:SetTall(logoImage:GetTall() + padding)
|
||||
else
|
||||
local newHeight = padding
|
||||
local subtitle = L2("schemaDesc") or Schema.description
|
||||
|
||||
local titleLabel = logoPanel:Add("DLabel")
|
||||
titleLabel:SetTextColor(color_white)
|
||||
titleLabel:SetFont("ixTitleFont")
|
||||
titleLabel:SetText(L2("schemaName") or Schema.name or L"unknown")
|
||||
titleLabel:SizeToContents()
|
||||
titleLabel:SetPos(halfWidth - titleLabel:GetWide() * 0.5, halfPadding)
|
||||
titleLabel:SetPaintedManually(true)
|
||||
newHeight = newHeight + titleLabel:GetTall()
|
||||
|
||||
if (subtitle) then
|
||||
local subtitleLabel = logoPanel:Add("DLabel")
|
||||
subtitleLabel:SetTextColor(color_white)
|
||||
subtitleLabel:SetFont("ixSubTitleFont")
|
||||
subtitleLabel:SetText(subtitle)
|
||||
subtitleLabel:SizeToContents()
|
||||
subtitleLabel:SetPos(halfWidth - subtitleLabel:GetWide() * 0.5, 0)
|
||||
subtitleLabel:MoveBelow(titleLabel)
|
||||
subtitleLabel:SetPaintedManually(true)
|
||||
newHeight = newHeight + subtitleLabel:GetTall()
|
||||
end
|
||||
|
||||
logoPanel:SetTall(newHeight)
|
||||
end
|
||||
|
||||
-- button list
|
||||
self.mainButtonList = self:Add("ixCharMenuButtonList")
|
||||
self.mainButtonList:Dock(LEFT)
|
||||
|
||||
-- create character button
|
||||
local createButton = self.mainButtonList:Add("ixMenuButton")
|
||||
createButton:SetText("create")
|
||||
createButton:SizeToContents()
|
||||
createButton.DoClick = function()
|
||||
local maximum = hook.Run("GetMaxPlayerCharacter", LocalPlayer()) or ix.config.Get("maxCharacters", 5)
|
||||
-- don't allow creation if we've hit the character limit
|
||||
if (#ix.characters >= maximum) then
|
||||
self:GetParent():ShowNotice(3, L("maxCharacters"))
|
||||
return
|
||||
end
|
||||
|
||||
self:Dim()
|
||||
parent.newCharacterPanel:SetActiveSubpanel("faction", 0)
|
||||
parent.newCharacterPanel:SlideUp()
|
||||
end
|
||||
|
||||
-- load character button
|
||||
self.loadButton = self.mainButtonList:Add("ixMenuButton")
|
||||
self.loadButton:SetText("load")
|
||||
self.loadButton:SizeToContents()
|
||||
self.loadButton.DoClick = function()
|
||||
self:Dim()
|
||||
parent.loadCharacterPanel:SlideUp()
|
||||
end
|
||||
|
||||
if (!bHasCharacter) then
|
||||
self.loadButton:SetDisabled(true)
|
||||
end
|
||||
|
||||
-- community button
|
||||
local extraURL = ix.config.Get("communityURL", "")
|
||||
local extraText = ix.config.Get("communityText", "@community")
|
||||
|
||||
if (extraURL != "" and extraText != "") then
|
||||
if (extraText:sub(1, 1) == "@") then
|
||||
extraText = L(extraText:sub(2))
|
||||
end
|
||||
|
||||
local extraButton = self.mainButtonList:Add("ixMenuButton")
|
||||
extraButton:SetText(extraText, true)
|
||||
extraButton:SizeToContents()
|
||||
extraButton.DoClick = function()
|
||||
gui.OpenURL(extraURL)
|
||||
end
|
||||
end
|
||||
|
||||
-- leave/return button
|
||||
self.returnButton = self.mainButtonList:Add("ixMenuButton")
|
||||
self:UpdateReturnButton()
|
||||
self.returnButton.DoClick = function()
|
||||
if (self.bUsingCharacter) then
|
||||
parent:Close()
|
||||
else
|
||||
RunConsoleCommand("disconnect")
|
||||
end
|
||||
end
|
||||
|
||||
self.mainButtonList:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:UpdateReturnButton(bValue)
|
||||
if (bValue == nil) then
|
||||
bValue = self.bUsingCharacter
|
||||
end
|
||||
|
||||
self.returnButton:SetText(bValue and "return" or "leave")
|
||||
self.returnButton:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:OnDim()
|
||||
-- disable input on this panel since it will still be in the background while invisible - prone to stray clicks if the
|
||||
-- panels overtop slide out of the way
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
end
|
||||
|
||||
function PANEL:OnUndim()
|
||||
self:SetMouseInputEnabled(true)
|
||||
self:SetKeyboardInputEnabled(true)
|
||||
|
||||
-- we may have just deleted a character so update the status of the return button
|
||||
self.bUsingCharacter = LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()
|
||||
self:UpdateReturnButton()
|
||||
end
|
||||
|
||||
function PANEL:OnClose()
|
||||
for _, v in pairs(self:GetChildren()) do
|
||||
if (IsValid(v)) then
|
||||
v:SetVisible(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout(width, height)
|
||||
local padding = self:GetPadding()
|
||||
|
||||
self.mainButtonList:SetPos(padding, height - self.mainButtonList:GetTall() - padding)
|
||||
end
|
||||
|
||||
vgui.Register("ixCharMenuMain", PANEL, "ixCharMenuPanel")
|
||||
|
||||
-- container panel
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
if (IsValid(ix.gui.loading)) then
|
||||
ix.gui.loading:Remove()
|
||||
end
|
||||
|
||||
if (IsValid(ix.gui.characterMenu)) then
|
||||
if (IsValid(ix.gui.characterMenu.channel)) then
|
||||
ix.gui.characterMenu.channel:Stop()
|
||||
end
|
||||
|
||||
ix.gui.characterMenu:Remove()
|
||||
end
|
||||
|
||||
self:SetSize(ScrW(), ScrH())
|
||||
self:SetPos(0, 0)
|
||||
|
||||
-- main menu panel
|
||||
self.mainPanel = self:Add("ixCharMenuMain")
|
||||
|
||||
-- new character panel
|
||||
self.newCharacterPanel = self:Add("ixCharMenuNew")
|
||||
self.newCharacterPanel:SlideDown(0)
|
||||
|
||||
-- load character panel
|
||||
self.loadCharacterPanel = self:Add("ixCharMenuLoad")
|
||||
self.loadCharacterPanel:SlideDown(0)
|
||||
|
||||
-- notice bar
|
||||
self.notice = self:Add("ixNoticeBar")
|
||||
|
||||
-- finalization
|
||||
self:MakePopup()
|
||||
self.currentAlpha = 255
|
||||
self.volume = 0
|
||||
|
||||
ix.gui.characterMenu = self
|
||||
|
||||
if (!IsValid(ix.gui.intro)) then
|
||||
self:PlayMusic()
|
||||
end
|
||||
|
||||
hook.Run("OnCharacterMenuCreated", self)
|
||||
end
|
||||
|
||||
function PANEL:PlayMusic()
|
||||
local path = "sound/" .. ix.config.Get("music")
|
||||
local url = path:match("http[s]?://.+")
|
||||
local play = url and sound.PlayURL or sound.PlayFile
|
||||
path = url and url or path
|
||||
|
||||
play(path, "noplay", function(channel, error, message)
|
||||
if (!IsValid(channel)) then
|
||||
return
|
||||
end
|
||||
|
||||
channel:SetVolume(self.volume or 0)
|
||||
channel:Play()
|
||||
|
||||
self.channel = channel
|
||||
|
||||
self:CreateAnimation(audioFadeInTime, {
|
||||
index = 10,
|
||||
target = {volume = 1},
|
||||
|
||||
Think = function(animation, panel)
|
||||
if (IsValid(panel.channel)) then
|
||||
panel.channel:SetVolume(self.volume * 0.5)
|
||||
end
|
||||
end
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
function PANEL:ShowNotice(type, text)
|
||||
self.notice:SetType(type)
|
||||
self.notice:SetText(text)
|
||||
self.notice:Show()
|
||||
end
|
||||
|
||||
function PANEL:HideNotice()
|
||||
if (IsValid(self.notice) and !self.notice:GetHidden()) then
|
||||
self.notice:Slide("up", 0.5, true)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnCharacterDeleted(character)
|
||||
if (#ix.characters == 0) then
|
||||
self.mainPanel.loadButton:SetDisabled(true)
|
||||
self.mainPanel:Undim() -- undim since the load panel will slide down
|
||||
else
|
||||
self.mainPanel.loadButton:SetDisabled(false)
|
||||
end
|
||||
|
||||
self.loadCharacterPanel:OnCharacterDeleted(character)
|
||||
end
|
||||
|
||||
function PANEL:OnCharacterLoadFailed(error)
|
||||
self.loadCharacterPanel:SetMouseInputEnabled(true)
|
||||
self.loadCharacterPanel:SlideUp()
|
||||
self:ShowNotice(3, error)
|
||||
end
|
||||
|
||||
function PANEL:IsClosing()
|
||||
return self.bClosing
|
||||
end
|
||||
|
||||
function PANEL:Close(bFromMenu)
|
||||
self.bClosing = true
|
||||
self.bFromMenu = bFromMenu
|
||||
|
||||
local fadeOutTime = animationTime * 8
|
||||
|
||||
self:CreateAnimation(fadeOutTime, {
|
||||
index = 1,
|
||||
target = {currentAlpha = 0},
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.currentAlpha)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
panel:Remove()
|
||||
end
|
||||
})
|
||||
|
||||
self:CreateAnimation(fadeOutTime - 0.1, {
|
||||
index = 10,
|
||||
target = {volume = 0},
|
||||
|
||||
Think = function(animation, panel)
|
||||
if (IsValid(panel.channel)) then
|
||||
panel.channel:SetVolume(self.volume * 0.5)
|
||||
end
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
if (IsValid(panel.channel)) then
|
||||
panel.channel:Stop()
|
||||
panel.channel = nil
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- hide children if we're already dimmed
|
||||
if (bFromMenu) then
|
||||
for _, v in pairs(self:GetChildren()) do
|
||||
if (IsValid(v)) then
|
||||
v:SetVisible(false)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- fade out the main panel quicker because it significantly blocks the screen
|
||||
self.mainPanel.currentAlpha = 255
|
||||
|
||||
self.mainPanel:CreateAnimation(animationTime * 2, {
|
||||
target = {currentAlpha = 0},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.currentAlpha)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
panel:SetVisible(false)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
-- relinquish mouse control
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
gui.EnableScreenClicker(false)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
surface.SetTexture(gradient)
|
||||
surface.SetDrawColor(0, 0, 0, 255)
|
||||
surface.DrawTexturedRect(0, 0, width, height)
|
||||
|
||||
if (!ix.option.Get("cheapBlur", false)) then
|
||||
surface.SetDrawColor(0, 0, 0, 150)
|
||||
surface.DrawTexturedRect(0, 0, width, height)
|
||||
ix.util.DrawBlur(self, Lerp((self.currentAlpha - 200) / 255, 0, 10))
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:PaintOver(width, height)
|
||||
if (self.bClosing and self.bFromMenu) then
|
||||
surface.SetDrawColor(color_black)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixCharMenu", PANEL, "EditablePanel")
|
||||
|
||||
if (IsValid(ix.gui.characterMenu)) then
|
||||
ix.gui.characterMenu:Remove()
|
||||
|
||||
--TODO: REMOVE ME
|
||||
ix.gui.characterMenu = vgui.Create("ixCharMenu")
|
||||
end
|
||||
509
gamemodes/helix/gamemode/core/derma/cl_charcreate.lua
Normal file
509
gamemodes/helix/gamemode/core/derma/cl_charcreate.lua
Normal file
@@ -0,0 +1,509 @@
|
||||
--[[
|
||||
| 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 padding = ScreenScale(32)
|
||||
|
||||
-- create character panel
|
||||
DEFINE_BASECLASS("ixCharMenuPanel")
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
local parent = self:GetParent()
|
||||
local halfWidth = parent:GetWide() * 0.5 - (padding * 2)
|
||||
local halfHeight = parent:GetTall() * 0.5 - (padding * 2)
|
||||
local modelFOV = (ScrW() > ScrH() * 1.8) and 100 or 78
|
||||
|
||||
self:ResetPayload(true)
|
||||
|
||||
self.factionButtons = {}
|
||||
self.repopulatePanels = {}
|
||||
|
||||
-- faction selection subpanel
|
||||
self.factionPanel = self:AddSubpanel("faction", true)
|
||||
self.factionPanel:SetTitle("chooseFaction")
|
||||
self.factionPanel.OnSetActive = function()
|
||||
-- if we only have one faction, we are always selecting that one so we can skip to the description section
|
||||
if (#self.factionButtons == 1) then
|
||||
self:SetActiveSubpanel("description", 0)
|
||||
end
|
||||
end
|
||||
|
||||
local modelList = self.factionPanel:Add("Panel")
|
||||
modelList:Dock(RIGHT)
|
||||
modelList:SetSize(halfWidth + padding * 2, halfHeight)
|
||||
|
||||
local proceed = modelList:Add("ixMenuButton")
|
||||
proceed:SetText("proceed")
|
||||
proceed:SetContentAlignment(6)
|
||||
proceed:Dock(BOTTOM)
|
||||
proceed:SizeToContents()
|
||||
proceed.DoClick = function()
|
||||
self.progress:IncrementProgress()
|
||||
|
||||
self:Populate()
|
||||
self:SetActiveSubpanel("description")
|
||||
end
|
||||
|
||||
self.factionModel = modelList:Add("ixModelPanel")
|
||||
self.factionModel:Dock(FILL)
|
||||
self.factionModel:SetModel("models/error.mdl")
|
||||
self.factionModel:SetFOV(modelFOV)
|
||||
self.factionModel.PaintModel = self.factionModel.Paint
|
||||
|
||||
self.factionButtonsPanel = self.factionPanel:Add("ixCharMenuButtonList")
|
||||
self.factionButtonsPanel:SetWide(halfWidth)
|
||||
self.factionButtonsPanel:Dock(FILL)
|
||||
|
||||
local factionBack = self.factionPanel:Add("ixMenuButton")
|
||||
factionBack:SetText("return")
|
||||
factionBack:SizeToContents()
|
||||
factionBack:Dock(BOTTOM)
|
||||
factionBack.DoClick = function()
|
||||
self.progress:DecrementProgress()
|
||||
|
||||
self:SetActiveSubpanel("faction", 0)
|
||||
self:SlideDown()
|
||||
|
||||
parent.mainPanel:Undim()
|
||||
end
|
||||
|
||||
-- character customization subpanel
|
||||
self.description = self:AddSubpanel("description")
|
||||
self.description:SetTitle("chooseDescription")
|
||||
|
||||
local descriptionModelList = self.description:Add("Panel")
|
||||
descriptionModelList:Dock(LEFT)
|
||||
descriptionModelList:SetSize(halfWidth, halfHeight)
|
||||
|
||||
local descriptionBack = descriptionModelList:Add("ixMenuButton")
|
||||
descriptionBack:SetText("return")
|
||||
descriptionBack:SetContentAlignment(4)
|
||||
descriptionBack:SizeToContents()
|
||||
descriptionBack:Dock(BOTTOM)
|
||||
descriptionBack.DoClick = function()
|
||||
self.progress:DecrementProgress()
|
||||
|
||||
if (#self.factionButtons == 1) then
|
||||
factionBack:DoClick()
|
||||
else
|
||||
self:SetActiveSubpanel("faction")
|
||||
end
|
||||
end
|
||||
|
||||
self.descriptionModel = descriptionModelList:Add("ixModelPanel")
|
||||
self.descriptionModel:Dock(FILL)
|
||||
self.descriptionModel:SetModel(self.factionModel:GetModel())
|
||||
self.descriptionModel:SetFOV(modelFOV - 13)
|
||||
self.descriptionModel.PaintModel = self.descriptionModel.Paint
|
||||
|
||||
self.descriptionPanel = self.description:Add("Panel")
|
||||
self.descriptionPanel:SetWide(halfWidth + padding * 2)
|
||||
self.descriptionPanel:Dock(RIGHT)
|
||||
|
||||
local descriptionProceed = self.descriptionPanel:Add("ixMenuButton")
|
||||
descriptionProceed:SetText("proceed")
|
||||
descriptionProceed:SetContentAlignment(6)
|
||||
descriptionProceed:SizeToContents()
|
||||
descriptionProceed:Dock(BOTTOM)
|
||||
descriptionProceed.DoClick = function()
|
||||
if (self:VerifyProgression("description")) then
|
||||
-- there are no panels on the attributes section other than the create button, so we can just create the character
|
||||
if (#self.attributesPanel:GetChildren() < 2) then
|
||||
self:SendPayload()
|
||||
return
|
||||
end
|
||||
|
||||
self.progress:IncrementProgress()
|
||||
self:SetActiveSubpanel("attributes")
|
||||
end
|
||||
end
|
||||
|
||||
-- attributes subpanel
|
||||
self.attributes = self:AddSubpanel("attributes")
|
||||
self.attributes:SetTitle("chooseSkills")
|
||||
|
||||
local attributesModelList = self.attributes:Add("Panel")
|
||||
attributesModelList:Dock(LEFT)
|
||||
attributesModelList:SetSize(halfWidth, halfHeight)
|
||||
|
||||
local attributesBack = attributesModelList:Add("ixMenuButton")
|
||||
attributesBack:SetText("return")
|
||||
attributesBack:SetContentAlignment(4)
|
||||
attributesBack:SizeToContents()
|
||||
attributesBack:Dock(BOTTOM)
|
||||
attributesBack.DoClick = function()
|
||||
self.progress:DecrementProgress()
|
||||
self:SetActiveSubpanel("description")
|
||||
end
|
||||
|
||||
self.attributesModel = attributesModelList:Add("ixModelPanel")
|
||||
self.attributesModel:Dock(FILL)
|
||||
self.attributesModel:SetModel(self.factionModel:GetModel())
|
||||
self.attributesModel:SetFOV(modelFOV - 13)
|
||||
self.attributesModel.PaintModel = self.attributesModel.Paint
|
||||
|
||||
self.attributesPanel = self.attributes:Add("Panel")
|
||||
self.attributesPanel:SetWide(halfWidth + padding * 2)
|
||||
self.attributesPanel:Dock(RIGHT)
|
||||
|
||||
local create = self.attributesPanel:Add("ixMenuButton")
|
||||
create:SetText("finish")
|
||||
create:SetContentAlignment(6)
|
||||
create:SizeToContents()
|
||||
create:Dock(BOTTOM)
|
||||
create.DoClick = function()
|
||||
self:SendPayload()
|
||||
end
|
||||
|
||||
-- creation progress panel
|
||||
self.progress = self:Add("ixSegmentedProgress")
|
||||
self.progress:SetBarColor(ix.config.Get("color"))
|
||||
self.progress:SetSize(parent:GetWide(), 0)
|
||||
self.progress:SizeToContents()
|
||||
self.progress:SetPos(0, parent:GetTall() - self.progress:GetTall())
|
||||
|
||||
-- setup payload hooks
|
||||
self:AddPayloadHook("model", function(value)
|
||||
local faction = ix.faction.indices[self.payload.faction]
|
||||
|
||||
if (faction) then
|
||||
local model = faction:GetModels(LocalPlayer())[value]
|
||||
|
||||
-- assuming bodygroups
|
||||
if (istable(model)) then
|
||||
self.factionModel:SetModel(model[1], model[2] or 0, model[3])
|
||||
self.descriptionModel:SetModel(model[1], model[2] or 0, model[3])
|
||||
self.attributesModel:SetModel(model[1], model[2] or 0, model[3])
|
||||
else
|
||||
self.factionModel:SetModel(model)
|
||||
self.descriptionModel:SetModel(model)
|
||||
self.attributesModel:SetModel(model)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- setup character creation hooks
|
||||
net.Receive("ixCharacterAuthed", function()
|
||||
timer.Remove("ixCharacterCreateTimeout")
|
||||
self.awaitingResponse = false
|
||||
|
||||
local id = net.ReadUInt(32)
|
||||
local indices = net.ReadUInt(6)
|
||||
local charList = {}
|
||||
|
||||
for _ = 1, indices do
|
||||
charList[#charList + 1] = net.ReadUInt(32)
|
||||
end
|
||||
|
||||
ix.characters = charList
|
||||
|
||||
self:SlideDown()
|
||||
|
||||
if (!IsValid(self) or !IsValid(parent)) then
|
||||
return
|
||||
end
|
||||
|
||||
if (LocalPlayer():GetCharacter()) then
|
||||
parent.mainPanel:Undim()
|
||||
parent:ShowNotice(2, L("charCreated"))
|
||||
elseif (id) then
|
||||
self.bMenuShouldClose = true
|
||||
|
||||
net.Start("ixCharacterChoose")
|
||||
net.WriteUInt(id, 32)
|
||||
net.SendToServer()
|
||||
else
|
||||
self:SlideDown()
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("ixCharacterAuthFailed", function()
|
||||
timer.Remove("ixCharacterCreateTimeout")
|
||||
self.awaitingResponse = false
|
||||
|
||||
local fault = net.ReadString()
|
||||
local args = net.ReadTable()
|
||||
|
||||
self:SlideDown()
|
||||
|
||||
parent.mainPanel:Undim()
|
||||
parent:ShowNotice(3, L(fault, unpack(args)))
|
||||
end)
|
||||
end
|
||||
|
||||
function PANEL:SendPayload()
|
||||
if (self.awaitingResponse or !self:VerifyProgression()) then
|
||||
return
|
||||
end
|
||||
|
||||
self.awaitingResponse = true
|
||||
|
||||
timer.Create("ixCharacterCreateTimeout", 10, 1, function()
|
||||
if (IsValid(self) and self.awaitingResponse) then
|
||||
local parent = self:GetParent()
|
||||
|
||||
self.awaitingResponse = false
|
||||
self:SlideDown()
|
||||
|
||||
parent.mainPanel:Undim()
|
||||
parent:ShowNotice(3, L("unknownError"))
|
||||
end
|
||||
end)
|
||||
|
||||
self.payload:Prepare()
|
||||
|
||||
net.Start("ixCharacterCreate")
|
||||
net.WriteUInt(table.Count(self.payload), 8)
|
||||
|
||||
for k, v in pairs(self.payload) do
|
||||
net.WriteString(k)
|
||||
net.WriteType(v)
|
||||
end
|
||||
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function PANEL:OnSlideUp()
|
||||
self:ResetPayload()
|
||||
self:Populate()
|
||||
self.progress:SetProgress(1)
|
||||
|
||||
-- the faction subpanel will skip to next subpanel if there is only one faction to choose from,
|
||||
-- so we don't have to worry about it here
|
||||
self:SetActiveSubpanel("faction", 0)
|
||||
end
|
||||
|
||||
function PANEL:OnSlideDown()
|
||||
end
|
||||
|
||||
function PANEL:ResetPayload(bWithHooks)
|
||||
if (bWithHooks) then
|
||||
self.hooks = {}
|
||||
end
|
||||
|
||||
self.payload = {}
|
||||
|
||||
-- TODO: eh..
|
||||
function self.payload.Set(payload, key, value)
|
||||
self:SetPayload(key, value)
|
||||
end
|
||||
|
||||
function self.payload.AddHook(payload, key, callback)
|
||||
self:AddPayloadHook(key, callback)
|
||||
end
|
||||
|
||||
function self.payload.Prepare(payload)
|
||||
self.payload.Set = nil
|
||||
self.payload.AddHook = nil
|
||||
self.payload.Prepare = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetPayload(key, value)
|
||||
self.payload[key] = value
|
||||
self:RunPayloadHook(key, value)
|
||||
end
|
||||
|
||||
function PANEL:AddPayloadHook(key, callback)
|
||||
if (!self.hooks[key]) then
|
||||
self.hooks[key] = {}
|
||||
end
|
||||
|
||||
self.hooks[key][#self.hooks[key] + 1] = callback
|
||||
end
|
||||
|
||||
function PANEL:RunPayloadHook(key, value)
|
||||
local hooks = self.hooks[key] or {}
|
||||
|
||||
for _, v in ipairs(hooks) do
|
||||
v(value)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:GetContainerPanel(name)
|
||||
-- TODO: yuck
|
||||
if (name == "description") then
|
||||
return self.descriptionPanel
|
||||
elseif (name == "attributes") then
|
||||
return self.attributesPanel
|
||||
end
|
||||
|
||||
return self.descriptionPanel
|
||||
end
|
||||
|
||||
function PANEL:AttachCleanup(panel)
|
||||
self.repopulatePanels[#self.repopulatePanels + 1] = panel
|
||||
end
|
||||
|
||||
function PANEL:Populate()
|
||||
if (!self.bInitialPopulate) then
|
||||
-- setup buttons for the faction panel
|
||||
-- TODO: make this a bit less janky
|
||||
local lastSelected
|
||||
|
||||
for _, v in pairs(self.factionButtons) do
|
||||
if (v:GetSelected()) then
|
||||
lastSelected = v.faction
|
||||
end
|
||||
|
||||
if (IsValid(v)) then
|
||||
v:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.factionButtons = {}
|
||||
|
||||
for _, v in SortedPairs(ix.faction.teams) do
|
||||
if (ix.faction.HasWhitelist(v.index)) then
|
||||
local button = self.factionButtonsPanel:Add("ixMenuSelectionButton")
|
||||
button:SetBackgroundColor(v.color or color_white)
|
||||
button:SetText(L(v.name):utf8upper())
|
||||
button:SizeToContents()
|
||||
button:SetButtonList(self.factionButtons)
|
||||
button.faction = v.index
|
||||
button.OnSelected = function(panel)
|
||||
local faction = ix.faction.indices[panel.faction]
|
||||
local models = faction:GetModels(LocalPlayer())
|
||||
|
||||
self.payload:Set("faction", panel.faction)
|
||||
self.payload:Set("model", math.random(1, #models))
|
||||
end
|
||||
|
||||
if ((lastSelected and lastSelected == v.index) or (!lastSelected and v.isDefault)) then
|
||||
button:SetSelected(true)
|
||||
lastSelected = v.index
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- remove panels created for character vars
|
||||
for i = 1, #self.repopulatePanels do
|
||||
self.repopulatePanels[i]:Remove()
|
||||
end
|
||||
|
||||
self.repopulatePanels = {}
|
||||
|
||||
-- payload is empty because we attempted to send it - for whatever reason we're back here again so we need to repopulate
|
||||
if (!self.payload.faction) then
|
||||
for _, v in pairs(self.factionButtons) do
|
||||
if (v:GetSelected()) then
|
||||
v:SetSelected(true)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.factionButtonsPanel:SizeToContents()
|
||||
|
||||
local zPos = 1
|
||||
|
||||
-- set up character vars
|
||||
for k, v in SortedPairsByMemberValue(ix.char.vars, "index") do
|
||||
if (!v.bNoDisplay and k != "__SortedIndex") then
|
||||
local container = self:GetContainerPanel(v.category or "description")
|
||||
|
||||
if (v.ShouldDisplay and v:ShouldDisplay(container, self.payload) == false) then
|
||||
continue
|
||||
end
|
||||
|
||||
local panel
|
||||
|
||||
-- if the var has a custom way of displaying, we'll use that instead
|
||||
if (v.OnDisplay) then
|
||||
panel = v:OnDisplay(container, self.payload)
|
||||
elseif (isstring(v.default)) then
|
||||
panel = container:Add("ixTextEntry")
|
||||
panel:Dock(TOP)
|
||||
panel:SetFont("ixMenuButtonHugeFont")
|
||||
panel:SetUpdateOnType(true)
|
||||
panel.OnValueChange = function(this, text)
|
||||
self.payload:Set(k, text)
|
||||
end
|
||||
end
|
||||
|
||||
if (IsValid(panel)) then
|
||||
-- add label for entry
|
||||
local label = container:Add("DLabel")
|
||||
label:SetFont("ixMenuButtonLabelFont")
|
||||
label:SetText(L(k):utf8upper())
|
||||
label:SizeToContents()
|
||||
label:DockMargin(0, 16, 0, 2)
|
||||
label:Dock(TOP)
|
||||
|
||||
-- we need to set the docking order so the label is above the panel
|
||||
label:SetZPos(zPos - 1)
|
||||
panel:SetZPos(zPos)
|
||||
|
||||
self:AttachCleanup(label)
|
||||
self:AttachCleanup(panel)
|
||||
|
||||
if (v.OnPostSetup) then
|
||||
v:OnPostSetup(panel, self.payload)
|
||||
end
|
||||
|
||||
zPos = zPos + 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (!self.bInitialPopulate) then
|
||||
-- setup progress bar segments
|
||||
if (#self.factionButtons > 1) then
|
||||
self.progress:AddSegment("@faction")
|
||||
end
|
||||
|
||||
self.progress:AddSegment("@description")
|
||||
|
||||
if (#self.attributesPanel:GetChildren() > 1) then
|
||||
self.progress:AddSegment("@skills")
|
||||
end
|
||||
|
||||
-- we don't need to show the progress bar if there's only one segment
|
||||
if (#self.progress:GetSegments() == 1) then
|
||||
self.progress:SetVisible(false)
|
||||
end
|
||||
end
|
||||
|
||||
self.bInitialPopulate = true
|
||||
end
|
||||
|
||||
function PANEL:VerifyProgression(name)
|
||||
for k, v in SortedPairsByMemberValue(ix.char.vars, "index") do
|
||||
if (name ~= nil and (v.category or "description") != name) then
|
||||
continue
|
||||
end
|
||||
|
||||
local value = self.payload[k]
|
||||
|
||||
if (!v.bNoDisplay or v.OnValidate) then
|
||||
if (v.OnValidate) then
|
||||
local result = {v:OnValidate(value, self.payload, LocalPlayer())}
|
||||
|
||||
if (result[1] == false) then
|
||||
self:GetParent():ShowNotice(3, L(unpack(result, 2)))
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
self.payload[k] = value
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("PaintCharacterCreateBackground", self, width, height)
|
||||
BaseClass.Paint(self, width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixCharMenuNew", PANEL, "ixCharMenuPanel")
|
||||
486
gamemodes/helix/gamemode/core/derma/cl_charload.lua
Normal file
486
gamemodes/helix/gamemode/core/derma/cl_charload.lua
Normal file
@@ -0,0 +1,486 @@
|
||||
--[[
|
||||
| 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 errorModel = "models/error.mdl"
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
|
||||
|
||||
local function SetCharacter(self, character)
|
||||
self.character = character
|
||||
|
||||
if (character) then
|
||||
self:SetModel(character:GetModel())
|
||||
self:SetSkin(character:GetData("skin", 0))
|
||||
|
||||
for i = 0, (self:GetNumBodyGroups() - 1) do
|
||||
self:SetBodygroup(i, 0)
|
||||
end
|
||||
|
||||
local bodygroups = character:GetData("groups", nil)
|
||||
|
||||
if (istable(bodygroups)) then
|
||||
for k, v in pairs(bodygroups) do
|
||||
self:SetBodygroup(k, v)
|
||||
end
|
||||
end
|
||||
else
|
||||
self:SetModel(errorModel)
|
||||
end
|
||||
end
|
||||
|
||||
local function GetCharacter(self)
|
||||
return self.character
|
||||
end
|
||||
|
||||
function PANEL:Init()
|
||||
self.activeCharacter = ClientsideModel(errorModel)
|
||||
self.activeCharacter:SetNoDraw(true)
|
||||
self.activeCharacter.SetCharacter = SetCharacter
|
||||
self.activeCharacter.GetCharacter = GetCharacter
|
||||
|
||||
self.lastCharacter = ClientsideModel(errorModel)
|
||||
self.lastCharacter:SetNoDraw(true)
|
||||
self.lastCharacter.SetCharacter = SetCharacter
|
||||
self.lastCharacter.GetCharacter = GetCharacter
|
||||
|
||||
self.animationTime = 0.5
|
||||
|
||||
self.shadeY = 0
|
||||
self.shadeHeight = 0
|
||||
|
||||
self.cameraPosition = Vector(80, 0, 35)
|
||||
self.cameraAngle = Angle(0, 180, 0)
|
||||
self.lastPaint = 0
|
||||
end
|
||||
|
||||
function PANEL:ResetSequence(model, lastModel)
|
||||
local sequence = model:LookupSequence("idle_unarmed")
|
||||
|
||||
if (sequence <= 0) then
|
||||
sequence = model:SelectWeightedSequence(ACT_IDLE)
|
||||
end
|
||||
|
||||
if (sequence > 0) then
|
||||
model:ResetSequence(sequence)
|
||||
else
|
||||
local found = false
|
||||
|
||||
for _, v in ipairs(model:GetSequenceList()) do
|
||||
if ((v:lower():find("idle") or v:lower():find("fly")) and v != "idlenoise") then
|
||||
model:ResetSequence(v)
|
||||
found = true
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if (!found) then
|
||||
model:ResetSequence(4)
|
||||
end
|
||||
end
|
||||
|
||||
model:SetIK(false)
|
||||
|
||||
-- copy cycle if we can to avoid a jarring transition from resetting the sequence
|
||||
if (lastModel) then
|
||||
model:SetCycle(lastModel:GetCycle())
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:RunAnimation(model)
|
||||
model:FrameAdvance((RealTime() - self.lastPaint) * 0.5)
|
||||
end
|
||||
|
||||
function PANEL:LayoutEntity(model)
|
||||
model:SetIK(false)
|
||||
|
||||
self:RunAnimation(model)
|
||||
end
|
||||
|
||||
function PANEL:SetActiveCharacter(character)
|
||||
self.shadeY = self:GetTall()
|
||||
self.shadeHeight = self:GetTall()
|
||||
|
||||
-- set character immediately if we're an error (something isn't selected yet)
|
||||
if (self.activeCharacter:GetModel() == errorModel) then
|
||||
self.activeCharacter:SetCharacter(character)
|
||||
self:ResetSequence(self.activeCharacter)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- if the animation is already playing, we update its parameters so we can avoid restarting
|
||||
local shade = self:GetTweenAnimation(1)
|
||||
local shadeHide = self:GetTweenAnimation(2)
|
||||
|
||||
if (shade) then
|
||||
shade.newCharacter = character
|
||||
return
|
||||
elseif (shadeHide) then
|
||||
shadeHide.queuedCharacter = character
|
||||
return
|
||||
end
|
||||
|
||||
self.lastCharacter:SetCharacter(self.activeCharacter:GetCharacter())
|
||||
self:ResetSequence(self.lastCharacter, self.activeCharacter)
|
||||
|
||||
shade = self:CreateAnimation(self.animationTime * 0.5, {
|
||||
index = 1,
|
||||
target = {
|
||||
shadeY = 0,
|
||||
shadeHeight = self:GetTall()
|
||||
},
|
||||
easing = "linear",
|
||||
|
||||
OnComplete = function(shadeAnimation, shadePanel)
|
||||
shadePanel.activeCharacter:SetCharacter(shadeAnimation.newCharacter)
|
||||
shadePanel:ResetSequence(shadePanel.activeCharacter)
|
||||
|
||||
shadePanel:CreateAnimation(shadePanel.animationTime, {
|
||||
index = 2,
|
||||
target = {shadeHeight = 0},
|
||||
easing = "outQuint",
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
if (animation.queuedCharacter) then
|
||||
panel:SetActiveCharacter(animation.queuedCharacter)
|
||||
else
|
||||
panel.lastCharacter:SetCharacter(nil)
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
})
|
||||
|
||||
shade.newCharacter = character
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
local x, y = self:LocalToScreen(0, 0)
|
||||
local bTransition = self.lastCharacter:GetModel() != errorModel
|
||||
local modelFOV = (ScrW() > ScrH() * 1.8) and 92 or 70
|
||||
|
||||
cam.Start3D(self.cameraPosition, self.cameraAngle, modelFOV, x, y, width, height)
|
||||
render.SuppressEngineLighting(true)
|
||||
render.SetLightingOrigin(self.activeCharacter:GetPos())
|
||||
|
||||
-- setup lighting
|
||||
render.SetModelLighting(0, 1.5, 1.5, 1.5)
|
||||
|
||||
for i = 1, 4 do
|
||||
render.SetModelLighting(i, 0.4, 0.4, 0.4)
|
||||
end
|
||||
|
||||
render.SetModelLighting(5, 0.04, 0.04, 0.04)
|
||||
|
||||
-- clip anything out of bounds
|
||||
local curparent = self
|
||||
local rightx = self:GetWide()
|
||||
local leftx = 0
|
||||
local topy = 0
|
||||
local bottomy = self:GetTall()
|
||||
local previous = curparent
|
||||
|
||||
while (curparent:GetParent() != nil) do
|
||||
local lastX, lastY = previous:GetPos()
|
||||
curparent = curparent:GetParent()
|
||||
|
||||
topy = math.Max(lastY, topy + lastY)
|
||||
leftx = math.Max(lastX, leftx + lastX)
|
||||
bottomy = math.Min(lastY + previous:GetTall(), bottomy + lastY)
|
||||
rightx = math.Min(lastX + previous:GetWide(), rightx + lastX)
|
||||
|
||||
previous = curparent
|
||||
end
|
||||
|
||||
ix.util.ResetStencilValues()
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilWriteMask(30)
|
||||
render.SetStencilTestMask(30)
|
||||
render.SetStencilReferenceValue(31)
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_ALWAYS)
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilZFailOperation(STENCIL_KEEP)
|
||||
|
||||
self:LayoutEntity(self.activeCharacter)
|
||||
|
||||
if (bTransition) then
|
||||
-- only need to layout while it's used
|
||||
self:LayoutEntity(self.lastCharacter)
|
||||
|
||||
render.SetScissorRect(leftx, topy, rightx, bottomy - (self:GetTall() - self.shadeHeight), true)
|
||||
self.lastCharacter:DrawModel()
|
||||
|
||||
render.SetScissorRect(leftx, topy + self.shadeHeight, rightx, bottomy, true)
|
||||
self.activeCharacter:DrawModel()
|
||||
|
||||
render.SetScissorRect(leftx, topy, rightx, bottomy, true)
|
||||
else
|
||||
self.activeCharacter:DrawModel()
|
||||
end
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_EQUAL)
|
||||
render.SetStencilPassOperation(STENCIL_KEEP)
|
||||
|
||||
cam.Start2D()
|
||||
derma.SkinFunc("PaintCharacterTransitionOverlay", self, 0, self.shadeY, width, self.shadeHeight)
|
||||
cam.End2D()
|
||||
render.SetStencilEnable(false)
|
||||
|
||||
render.SetScissorRect(0, 0, 0, 0, false)
|
||||
render.SuppressEngineLighting(false)
|
||||
cam.End3D()
|
||||
|
||||
self.lastPaint = RealTime()
|
||||
end
|
||||
|
||||
function PANEL:OnRemove()
|
||||
self.lastCharacter:Remove()
|
||||
self.activeCharacter:Remove()
|
||||
end
|
||||
|
||||
vgui.Register("ixCharMenuCarousel", PANEL, "Panel")
|
||||
|
||||
-- character load panel
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "backgroundFraction", "BackgroundFraction", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
local parent = self:GetParent()
|
||||
local padding = self:GetPadding()
|
||||
local halfWidth = parent:GetWide() * 0.5 - (padding * 2)
|
||||
local halfHeight = parent:GetTall() * 0.5 - (padding * 2)
|
||||
local modelFOV = (ScrW() > ScrH() * 1.8) and 102 or 78
|
||||
|
||||
self.animationTime = 1
|
||||
self.backgroundFraction = 1
|
||||
|
||||
-- main panel
|
||||
self.panel = self:AddSubpanel("main")
|
||||
self.panel:SetTitle("loadTitle")
|
||||
self.panel.OnSetActive = function()
|
||||
self:CreateAnimation(self.animationTime, {
|
||||
index = 2,
|
||||
target = {backgroundFraction = 1},
|
||||
easing = "outQuint",
|
||||
})
|
||||
end
|
||||
|
||||
-- character button list
|
||||
local controlList = self.panel:Add("Panel")
|
||||
controlList:Dock(LEFT)
|
||||
controlList:SetSize(halfWidth, halfHeight)
|
||||
|
||||
local back = controlList:Add("ixMenuButton")
|
||||
back:Dock(BOTTOM)
|
||||
back:SetText("return")
|
||||
back:SizeToContents()
|
||||
back.DoClick = function()
|
||||
self:SlideDown()
|
||||
parent.mainPanel:Undim()
|
||||
end
|
||||
|
||||
self.characterList = controlList:Add("ixCharMenuButtonList")
|
||||
self.characterList.buttons = {}
|
||||
self.characterList:Dock(FILL)
|
||||
|
||||
-- right-hand side with carousel and buttons
|
||||
local infoPanel = self.panel:Add("Panel")
|
||||
infoPanel:Dock(FILL)
|
||||
|
||||
local infoButtons = infoPanel:Add("Panel")
|
||||
infoButtons:Dock(BOTTOM)
|
||||
infoButtons:SetTall(back:GetTall()) -- hmm...
|
||||
|
||||
local continueButton = infoButtons:Add("ixMenuButton")
|
||||
continueButton:Dock(FILL)
|
||||
continueButton:SetText("choose")
|
||||
continueButton:SetContentAlignment(6)
|
||||
continueButton:SizeToContents()
|
||||
continueButton.DoClick = function()
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:Slide("down", self.animationTime, function()
|
||||
net.Start("ixCharacterChoose")
|
||||
net.WriteUInt(self.character:GetID(), 32)
|
||||
net.SendToServer()
|
||||
end, true)
|
||||
end
|
||||
|
||||
local deleteButton = infoButtons:Add("ixMenuButton")
|
||||
deleteButton:Dock(LEFT)
|
||||
deleteButton:SetText("delete")
|
||||
deleteButton:SetContentAlignment(5)
|
||||
deleteButton:SetTextInset(0, 0)
|
||||
deleteButton:SizeToContents()
|
||||
deleteButton:SetTextColor(derma.GetColor("Error", deleteButton))
|
||||
deleteButton.DoClick = function()
|
||||
self:SetActiveSubpanel("delete")
|
||||
end
|
||||
|
||||
self.carousel = infoPanel:Add("ixCharMenuCarousel")
|
||||
self.carousel:Dock(FILL)
|
||||
|
||||
-- character deletion panel
|
||||
self.delete = self:AddSubpanel("delete")
|
||||
self.delete:SetTitle(nil)
|
||||
self.delete.OnSetActive = function()
|
||||
self.deleteModel:SetModel(self.character:GetModel())
|
||||
self:CreateAnimation(self.animationTime, {
|
||||
index = 2,
|
||||
target = {backgroundFraction = 0},
|
||||
easing = "outQuint"
|
||||
})
|
||||
end
|
||||
|
||||
local deleteInfo = self.delete:Add("Panel")
|
||||
deleteInfo:SetSize(parent:GetWide() * 0.5, parent:GetTall())
|
||||
deleteInfo:Dock(LEFT)
|
||||
|
||||
local deleteReturn = deleteInfo:Add("ixMenuButton")
|
||||
deleteReturn:Dock(BOTTOM)
|
||||
deleteReturn:SetText("no")
|
||||
deleteReturn:SizeToContents()
|
||||
deleteReturn.DoClick = function()
|
||||
self:SetActiveSubpanel("main")
|
||||
end
|
||||
|
||||
local deleteConfirm = self.delete:Add("ixMenuButton")
|
||||
deleteConfirm:Dock(BOTTOM)
|
||||
deleteConfirm:SetText("yes")
|
||||
deleteConfirm:SetContentAlignment(6)
|
||||
deleteConfirm:SizeToContents()
|
||||
deleteConfirm:SetTextColor(derma.GetColor("Error", deleteConfirm))
|
||||
deleteConfirm.DoClick = function()
|
||||
local id = self.character:GetID()
|
||||
|
||||
parent:ShowNotice(1, L("deleteComplete", self.character:GetName()))
|
||||
self:Populate(id)
|
||||
self:SetActiveSubpanel("main")
|
||||
|
||||
net.Start("ixCharacterDelete")
|
||||
net.WriteUInt(id, 32)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
self.deleteModel = deleteInfo:Add("ixModelPanel")
|
||||
self.deleteModel:Dock(FILL)
|
||||
self.deleteModel:SetModel(errorModel)
|
||||
self.deleteModel:SetFOV(modelFOV)
|
||||
self.deleteModel.PaintModel = self.deleteModel.Paint
|
||||
|
||||
local deleteNag = self.delete:Add("Panel")
|
||||
deleteNag:SetTall(parent:GetTall() * 0.5)
|
||||
deleteNag:Dock(BOTTOM)
|
||||
|
||||
local deleteTitle = deleteNag:Add("DLabel")
|
||||
deleteTitle:SetFont("ixTitleFont")
|
||||
deleteTitle:SetText(L("areYouSure"):utf8upper())
|
||||
deleteTitle:SetTextColor(ix.config.Get("color"))
|
||||
deleteTitle:SizeToContents()
|
||||
deleteTitle:Dock(TOP)
|
||||
|
||||
local deleteText = deleteNag:Add("DLabel")
|
||||
deleteText:SetFont("ixMenuButtonFont")
|
||||
deleteText:SetText(L("deleteConfirm"))
|
||||
deleteText:SetTextColor(color_white)
|
||||
deleteText:SetContentAlignment(7)
|
||||
deleteText:Dock(FILL)
|
||||
|
||||
-- finalize setup
|
||||
self:SetActiveSubpanel("main", 0)
|
||||
end
|
||||
|
||||
function PANEL:OnCharacterDeleted(character)
|
||||
if (self.bActive and #ix.characters == 0) then
|
||||
self:SlideDown()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Populate(ignoreID)
|
||||
self.characterList:Clear()
|
||||
self.characterList.buttons = {}
|
||||
|
||||
local bSelected
|
||||
|
||||
-- loop backwards to preserve order since we're docking to the bottom
|
||||
for i = 1, #ix.characters do
|
||||
local id = ix.characters[i]
|
||||
local character = ix.char.loaded[id]
|
||||
|
||||
if (!character or character:GetID() == ignoreID) then
|
||||
continue
|
||||
end
|
||||
|
||||
local index = character:GetFaction()
|
||||
local faction = ix.faction.indices[index]
|
||||
local color = faction and faction.color or color_white
|
||||
|
||||
local button = self.characterList:Add("ixMenuSelectionButton")
|
||||
button:SetBackgroundColor(color)
|
||||
button:SetText(character:GetName())
|
||||
button:SizeToContents()
|
||||
button:SetButtonList(self.characterList.buttons)
|
||||
button.character = character
|
||||
button.OnSelected = function(panel)
|
||||
self:OnCharacterButtonSelected(panel)
|
||||
end
|
||||
|
||||
-- select currently loaded character if available
|
||||
local localCharacter = LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()
|
||||
|
||||
if (localCharacter and character:GetID() == localCharacter:GetID()) then
|
||||
button:SetSelected(true)
|
||||
self.characterList:ScrollToChild(button)
|
||||
|
||||
bSelected = true
|
||||
end
|
||||
end
|
||||
|
||||
if (!bSelected) then
|
||||
local buttons = self.characterList.buttons
|
||||
|
||||
if (#buttons > 0) then
|
||||
local button = buttons[#buttons]
|
||||
|
||||
button:SetSelected(true)
|
||||
self.characterList:ScrollToChild(button)
|
||||
else
|
||||
self.character = nil
|
||||
end
|
||||
end
|
||||
|
||||
self.characterList:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:OnSlideUp()
|
||||
self.bActive = true
|
||||
self:Populate()
|
||||
end
|
||||
|
||||
function PANEL:OnSlideDown()
|
||||
self.bActive = false
|
||||
end
|
||||
|
||||
function PANEL:OnCharacterButtonSelected(panel)
|
||||
self.carousel:SetActiveCharacter(panel.character)
|
||||
self.character = panel.character
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("PaintCharacterLoadBackground", self, width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixCharMenuLoad", PANEL, "ixCharMenuPanel")
|
||||
169
gamemodes/helix/gamemode/core/derma/cl_classes.lua
Normal file
169
gamemodes/helix/gamemode/core/derma/cl_classes.lua
Normal file
@@ -0,0 +1,169 @@
|
||||
--[[
|
||||
| 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 = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetTall(64)
|
||||
|
||||
local function AssignClick(panel)
|
||||
panel.OnMousePressed = function()
|
||||
self.pressing = -1
|
||||
self:OnClick()
|
||||
end
|
||||
|
||||
panel.OnMouseReleased = function()
|
||||
if (self.pressing) then
|
||||
self.pressing = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self.icon = self:Add("SpawnIcon")
|
||||
self.icon:SetSize(128, 64)
|
||||
self.icon:InvalidateLayout(true)
|
||||
self.icon:Dock(LEFT)
|
||||
self.icon.PaintOver = function(this, w, h)
|
||||
end
|
||||
AssignClick(self.icon)
|
||||
|
||||
self.limit = self:Add("DLabel")
|
||||
self.limit:Dock(RIGHT)
|
||||
self.limit:SetMouseInputEnabled(true)
|
||||
self.limit:SetCursor("hand")
|
||||
self.limit:SetExpensiveShadow(1, Color(0, 0, 60))
|
||||
self.limit:SetContentAlignment(5)
|
||||
self.limit:SetFont("ixMediumFont")
|
||||
self.limit:SetWide(64)
|
||||
AssignClick(self.limit)
|
||||
|
||||
self.label = self:Add("DLabel")
|
||||
self.label:Dock(FILL)
|
||||
self.label:SetMouseInputEnabled(true)
|
||||
self.label:SetCursor("hand")
|
||||
self.label:SetExpensiveShadow(1, Color(0, 0, 60))
|
||||
self.label:SetContentAlignment(5)
|
||||
self.label:SetFont("ixMediumFont")
|
||||
AssignClick(self.label)
|
||||
end
|
||||
|
||||
function PANEL:OnClick()
|
||||
ix.command.Send("BecomeClass", self.class)
|
||||
end
|
||||
|
||||
function PANEL:SetNumber(number)
|
||||
local limit = self.data.limit
|
||||
|
||||
if (limit > 0) then
|
||||
self.limit:SetText(Format("%s/%s", number, limit))
|
||||
else
|
||||
self.limit:SetText("∞")
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetClass(data)
|
||||
if (data.model) then
|
||||
local model = data.model
|
||||
if (istable(model)) then
|
||||
model = table.Random(model)
|
||||
end
|
||||
|
||||
self.icon:SetModel(model)
|
||||
else
|
||||
local char = LocalPlayer():GetCharacter()
|
||||
local model = LocalPlayer():GetModel()
|
||||
|
||||
if (char) then
|
||||
model = char:GetModel()
|
||||
end
|
||||
|
||||
self.icon:SetModel(model)
|
||||
end
|
||||
|
||||
self.label:SetText(L(data.name))
|
||||
self.data = data
|
||||
self.class = data.index
|
||||
|
||||
self:SetNumber(#ix.class.GetPlayers(data.index))
|
||||
end
|
||||
|
||||
vgui.Register("ixClassPanel", PANEL, "DPanel")
|
||||
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
ix.gui.classes = self
|
||||
|
||||
self:SetSize(self:GetParent():GetSize())
|
||||
|
||||
self.list = vgui.Create("DPanelList", self)
|
||||
self.list:Dock(FILL)
|
||||
self.list:EnableVerticalScrollbar()
|
||||
self.list:SetSpacing(5)
|
||||
self.list:SetPadding(5)
|
||||
|
||||
self.classPanels = {}
|
||||
self:LoadClasses()
|
||||
end
|
||||
|
||||
function PANEL:LoadClasses()
|
||||
self.list:Clear()
|
||||
|
||||
for k, v in ipairs(ix.class.list) do
|
||||
local no, why = ix.class.CanSwitchTo(LocalPlayer(), k)
|
||||
local itsFull = ("class is full" == why)
|
||||
|
||||
if (no or itsFull) then
|
||||
local panel = vgui.Create("ixClassPanel", self.list)
|
||||
panel:SetClass(v)
|
||||
table.insert(self.classPanels, panel)
|
||||
|
||||
self.list:AddItem(panel)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixClasses", PANEL, "EditablePanel")
|
||||
|
||||
hook.Add("CreateMenuButtons", "ixClasses", function(tabs)
|
||||
local cnt = table.Count(ix.class.list)
|
||||
|
||||
if (cnt <= 1) then return end
|
||||
|
||||
for k, _ in ipairs(ix.class.list) do
|
||||
if (!ix.class.CanSwitchTo(LocalPlayer(), k)) then
|
||||
continue
|
||||
else
|
||||
tabs["classes"] = function(container)
|
||||
container:Add("ixClasses")
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("ixClassUpdate", function()
|
||||
local client = net.ReadEntity()
|
||||
|
||||
if (ix.gui.classes and ix.gui.classes:IsVisible()) then
|
||||
if (client == LocalPlayer()) then
|
||||
ix.gui.classes:LoadClasses()
|
||||
else
|
||||
for _, v in ipairs(ix.gui.classes.classPanels) do
|
||||
local data = v.data
|
||||
|
||||
v:SetNumber(#ix.class.GetPlayers(data.index))
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
210
gamemodes/helix/gamemode/core/derma/cl_config.lua
Normal file
210
gamemodes/helix/gamemode/core/derma/cl_config.lua
Normal file
@@ -0,0 +1,210 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- config manager
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:Dock(FILL)
|
||||
self:SetSearchEnabled(true)
|
||||
|
||||
self:Populate()
|
||||
end
|
||||
|
||||
function PANEL:Populate()
|
||||
-- gather categories
|
||||
local categories = {}
|
||||
local categoryIndices = {}
|
||||
|
||||
for k, v in pairs(ix.config.stored) do
|
||||
local index = v.data and v.data.category or "misc"
|
||||
|
||||
categories[index] = categories[index] or {}
|
||||
categories[index][k] = v
|
||||
end
|
||||
|
||||
-- sort by category phrase
|
||||
for k, _ in pairs(categories) do
|
||||
categoryIndices[#categoryIndices + 1] = k
|
||||
end
|
||||
|
||||
table.sort(categoryIndices, function(a, b)
|
||||
return L(a) < L(b)
|
||||
end)
|
||||
|
||||
-- add panels
|
||||
for _, category in ipairs(categoryIndices) do
|
||||
local categoryPhrase = L(category)
|
||||
self:AddCategory(categoryPhrase)
|
||||
|
||||
-- we can use sortedpairs since configs don't have phrases to account for
|
||||
for k, v in SortedPairs(categories[category]) do
|
||||
if (isfunction(v.hidden) and v.hidden()) then
|
||||
continue
|
||||
end
|
||||
|
||||
local data = v.data.data
|
||||
local type = v.type
|
||||
local value = ix.util.SanitizeType(type, ix.config.Get(k))
|
||||
|
||||
local row = self:AddRow(type, categoryPhrase)
|
||||
row:SetText(ix.util.ExpandCamelCase(k))
|
||||
|
||||
-- type-specific properties
|
||||
if (type == ix.type.number) then
|
||||
row:SetMin(data and data.min or 0)
|
||||
row:SetMax(data and data.max or 1)
|
||||
row:SetDecimals(data and data.decimals or 0)
|
||||
end
|
||||
|
||||
row:SetValue(value, true)
|
||||
row:SetShowReset(value != v.default, k, v.default)
|
||||
|
||||
row.OnValueChanged = function(panel)
|
||||
local newValue = ix.util.SanitizeType(type, panel:GetValue())
|
||||
|
||||
panel:SetShowReset(newValue != v.default, k, v.default)
|
||||
|
||||
net.Start("ixConfigSet")
|
||||
net.WriteString(k)
|
||||
net.WriteType(newValue)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
row.OnResetClicked = function(panel)
|
||||
panel:SetValue(v.default, true)
|
||||
panel:SetShowReset(false)
|
||||
|
||||
net.Start("ixConfigSet")
|
||||
net.WriteString(k)
|
||||
net.WriteType(v.default)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
row:GetLabel():SetHelixTooltip(function(tooltip)
|
||||
local title = tooltip:AddRow("name")
|
||||
title:SetImportant()
|
||||
title:SetText(k)
|
||||
title:SizeToContents()
|
||||
title:SetMaxWidth(math.max(title:GetMaxWidth(), ScrW() * 0.5))
|
||||
|
||||
local description = tooltip:AddRow("description")
|
||||
description:SetText(v.description)
|
||||
description:SizeToContents()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
self:SizeToContents()
|
||||
end
|
||||
|
||||
vgui.Register("ixConfigManager", PANEL, "ixSettings")
|
||||
|
||||
-- plugin manager
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:Dock(FILL)
|
||||
self:SetSearchEnabled(true)
|
||||
|
||||
self.loadedCategory = L("loadedPlugins")
|
||||
self.unloadedCategory = L("unloadedPlugins")
|
||||
|
||||
if (!ix.gui.bReceivedUnloadedPlugins) then
|
||||
net.Start("ixConfigRequestUnloadedList")
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
self:Populate()
|
||||
end
|
||||
|
||||
function PANEL:OnPluginToggled(uniqueID, bEnabled)
|
||||
net.Start("ixConfigPluginToggle")
|
||||
net.WriteString(uniqueID)
|
||||
net.WriteBool(bEnabled)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function PANEL:Populate()
|
||||
self:AddCategory(self.loadedCategory)
|
||||
self:AddCategory(self.unloadedCategory)
|
||||
|
||||
-- add loaded plugins
|
||||
for k, v in SortedPairsByMemberValue(ix.plugin.list, "name") do
|
||||
local row = self:AddRow(ix.type.bool, self.loadedCategory)
|
||||
row.id = k
|
||||
|
||||
row.setting:SetEnabledText(L("on"):utf8upper())
|
||||
row.setting:SetDisabledText(L("off"):utf8upper())
|
||||
row.setting:SizeToContents()
|
||||
|
||||
-- if this plugin is not in the unloaded list currently, then it's queued for an unload
|
||||
row:SetValue(!ix.plugin.unloaded[k], true)
|
||||
row:SetText(v.name)
|
||||
|
||||
row.OnValueChanged = function(panel, bEnabled)
|
||||
self:OnPluginToggled(k, bEnabled)
|
||||
end
|
||||
|
||||
row:GetLabel():SetHelixTooltip(function(tooltip)
|
||||
local title = tooltip:AddRow("name")
|
||||
title:SetImportant()
|
||||
title:SetText(v.name)
|
||||
title:SizeToContents()
|
||||
title:SetMaxWidth(math.max(title:GetMaxWidth(), ScrW() * 0.5))
|
||||
|
||||
local description = tooltip:AddRow("description")
|
||||
description:SetText(v.description)
|
||||
description:SizeToContents()
|
||||
end)
|
||||
end
|
||||
|
||||
self:UpdateUnloaded(true)
|
||||
self:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:UpdatePlugin(uniqueID, bEnabled)
|
||||
for _, v in pairs(self:GetRows()) do
|
||||
if (v.id == uniqueID) then
|
||||
v:SetValue(bEnabled, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- called from Populate and from the ixConfigUnloadedList net message
|
||||
function PANEL:UpdateUnloaded(bNoSizeToContents)
|
||||
for _, v in pairs(self:GetRows()) do
|
||||
if (ix.plugin.unloaded[v.id]) then
|
||||
v:SetValue(false, true)
|
||||
end
|
||||
end
|
||||
|
||||
for k, _ in SortedPairs(ix.plugin.unloaded) do
|
||||
if (ix.plugin.list[k]) then
|
||||
-- if this plugin is in the loaded plugins list then it's queued for an unload - don't display it in this category
|
||||
continue
|
||||
end
|
||||
|
||||
local row = self:AddRow(ix.type.bool, self.unloadedCategory)
|
||||
row:SetText(k)
|
||||
row:SetValue(false, true)
|
||||
|
||||
row.OnValueChanged = function(panel, bEnabled)
|
||||
self:OnPluginToggled(k, bEnabled)
|
||||
end
|
||||
end
|
||||
|
||||
if (!bNoSizeToContents) then
|
||||
self:SizeToContents()
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixPluginManager", PANEL, "ixSettings")
|
||||
318
gamemodes/helix/gamemode/core/derma/cl_credits.lua
Normal file
318
gamemodes/helix/gamemode/core/derma/cl_credits.lua
Normal file
@@ -0,0 +1,318 @@
|
||||
--[[
|
||||
| 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 CREDITS = {
|
||||
{"Alex Grist", "76561197979205163", {"creditLeadDeveloper", "creditManager"}},
|
||||
{"Igor Radovanovic", "76561197990111113", {"creditLeadDeveloper", "creditUIDesigner"}},
|
||||
{"Jaydawg", "76561197970371430", {"creditTester"}}
|
||||
}
|
||||
|
||||
local SPECIALS = {
|
||||
{
|
||||
{"Luna", "76561197988658543"},
|
||||
{"Rain GBizzle", "76561198036111376"}
|
||||
},
|
||||
{
|
||||
{"Black Tea", "76561197999893894"}
|
||||
}
|
||||
}
|
||||
|
||||
local MISC = {
|
||||
{"nebulous", "Staff members finding bugs and providing input"},
|
||||
{"Contributors", "Ongoing support from various developers via GitHub"},
|
||||
{"NutScript", "Providing the base framework to build upon"}
|
||||
}
|
||||
|
||||
local url = "https://gethelix.co/"
|
||||
local padding = 32
|
||||
|
||||
-- logo
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetTall(ScrH() * 0.60)
|
||||
self:Dock(TOP)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("DrawHelixCurved", width * 0.5, height * 0.5, width * 0.25)
|
||||
|
||||
-- title
|
||||
surface.SetFont("ixIntroSubtitleFont")
|
||||
local text = L("helix"):lower()
|
||||
local textWidth, textHeight = surface.GetTextSize(text)
|
||||
|
||||
surface.SetTextColor(color_white)
|
||||
surface.SetTextPos(width * 0.5 - textWidth * 0.5, height * 0.5 - textHeight * 0.5)
|
||||
surface.DrawText(text)
|
||||
|
||||
-- version
|
||||
surface.SetFont("ixMenuMiniFont")
|
||||
surface.SetTextColor(200, 200, 200, 255)
|
||||
surface.SetTextPos(width * 0.5 + textWidth * 0.5, height * 0.5 - textHeight * 0.5)
|
||||
surface.DrawText(GAMEMODE.Version)
|
||||
end
|
||||
|
||||
vgui.Register("ixCreditsLogo", PANEL, "Panel")
|
||||
|
||||
-- nametag
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.name = self:Add("DLabel")
|
||||
self.name:SetFont("ixMenuButtonFontThick")
|
||||
|
||||
self.avatar = self:Add("AvatarImage")
|
||||
end
|
||||
|
||||
function PANEL:SetName(name)
|
||||
self.name:SetText(name)
|
||||
end
|
||||
|
||||
function PANEL:SetAvatar(steamid)
|
||||
self.avatar:SetSteamID(steamid, 64)
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout(width, height)
|
||||
self.name:SetPos(width - self.name:GetWide(), 0)
|
||||
self.avatar:MoveLeftOf(self.name, padding * 0.5)
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
self.name:SizeToContents()
|
||||
|
||||
local tall = self.name:GetTall()
|
||||
self.avatar:SetSize(tall, tall)
|
||||
self:SetSize(self.name:GetWide() + self.avatar:GetWide() + padding * 0.5, self.name:GetTall())
|
||||
end
|
||||
|
||||
vgui.Register("ixCreditsNametag", PANEL, "Panel")
|
||||
|
||||
-- name row
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:DockMargin(0, padding, 0, 0)
|
||||
self:Dock(TOP)
|
||||
|
||||
self.nametag = self:Add("ixCreditsNametag")
|
||||
|
||||
self.tags = self:Add("DLabel")
|
||||
self.tags:SetFont("ixMenuButtonFont")
|
||||
|
||||
self:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:SetName(name)
|
||||
self.nametag:SetName(name)
|
||||
end
|
||||
|
||||
function PANEL:SetAvatar(steamid)
|
||||
self.nametag:SetAvatar(steamid)
|
||||
end
|
||||
|
||||
function PANEL:SetTags(tags)
|
||||
for i = 1, #tags do
|
||||
tags[i] = L(tags[i])
|
||||
end
|
||||
|
||||
self.tags:SetText(table.concat(tags, "\n"))
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
surface.SetDrawColor(ix.config.Get("color"))
|
||||
surface.DrawRect(width * 0.5 - 1, 0, 1, height)
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout(width, height)
|
||||
self.nametag:SetPos(width * 0.5 - self.nametag:GetWide() - padding, 0)
|
||||
self.tags:SetPos(width * 0.5 + padding, 0)
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
self.nametag:SizeToContents()
|
||||
self.tags:SizeToContents()
|
||||
|
||||
self:SetTall(math.max(self.nametag:GetTall(), self.tags:GetTall()))
|
||||
end
|
||||
|
||||
vgui.Register("ixCreditsRow", PANEL, "Panel")
|
||||
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.left = {}
|
||||
self.right = {}
|
||||
end
|
||||
|
||||
function PANEL:AddLeft(name, steamid)
|
||||
local nametag = self:Add("ixCreditsNametag")
|
||||
nametag:SetName(name)
|
||||
nametag:SetAvatar(steamid)
|
||||
nametag:SizeToContents()
|
||||
|
||||
self.left[#self.left + 1] = nametag
|
||||
end
|
||||
|
||||
function PANEL:AddRight(name, steamid)
|
||||
local nametag = self:Add("ixCreditsNametag")
|
||||
nametag:SetName(name)
|
||||
nametag:SetAvatar(steamid)
|
||||
nametag:SizeToContents()
|
||||
|
||||
self.right[#self.right + 1] = nametag
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout(width, height)
|
||||
local y = 0
|
||||
|
||||
for _, v in ipairs(self.left) do
|
||||
v:SetPos(width * 0.25 - v:GetWide() * 0.5, y)
|
||||
y = y + v:GetTall() + padding
|
||||
end
|
||||
|
||||
y = 0
|
||||
|
||||
for _, v in ipairs(self.right) do
|
||||
v:SetPos(width * 0.75 - v:GetWide() * 0.5, y)
|
||||
y = y + v:GetTall() + padding
|
||||
end
|
||||
|
||||
if (IsValid(self.center)) then
|
||||
self.center:SetPos(width * 0.5 - self.center:GetWide() * 0.5, y)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
local heightLeft, heightRight, centerHeight = 0, 0, 0
|
||||
|
||||
if (#self.left > #self.right) then
|
||||
local center = self.left[#self.left]
|
||||
centerHeight = center:GetTall()
|
||||
|
||||
self.center = center
|
||||
self.left[#self.left] = nil
|
||||
elseif (#self.right > #self.left) then
|
||||
local center = self.right[#self.right]
|
||||
centerHeight = center:GetTall()
|
||||
|
||||
self.center = center
|
||||
self.right[#self.right] = nil
|
||||
end
|
||||
|
||||
for _, v in ipairs(self.left) do
|
||||
heightLeft = heightLeft + v:GetTall() + padding
|
||||
end
|
||||
|
||||
for _, v in ipairs(self.right) do
|
||||
heightRight = heightRight + v:GetTall() + padding
|
||||
end
|
||||
|
||||
self:SetTall(math.max(heightLeft, heightRight) + centerHeight)
|
||||
end
|
||||
|
||||
vgui.Register("ixCreditsSpecials", PANEL, "Panel")
|
||||
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:Add("ixCreditsLogo")
|
||||
|
||||
local link = self:Add("DLabel", self)
|
||||
link:SetFont("ixMenuMiniFont")
|
||||
link:SetTextColor(Color(200, 200, 200, 255))
|
||||
link:SetText(url)
|
||||
link:SetContentAlignment(5)
|
||||
link:Dock(TOP)
|
||||
link:SizeToContents()
|
||||
link:SetMouseInputEnabled(true)
|
||||
link:SetCursor("hand")
|
||||
link.OnMousePressed = function()
|
||||
gui.OpenURL(url)
|
||||
end
|
||||
|
||||
for _, v in ipairs(CREDITS) do
|
||||
local row = self:Add("ixCreditsRow")
|
||||
row:SetName(v[1])
|
||||
row:SetAvatar(v[2])
|
||||
row:SetTags(v[3])
|
||||
row:SizeToContents()
|
||||
end
|
||||
|
||||
local specials = self:Add("ixLabel")
|
||||
specials:SetFont("ixMenuButtonFont")
|
||||
specials:SetText(L("creditSpecial"):utf8upper())
|
||||
specials:SetTextColor(ix.config.Get("color"))
|
||||
specials:SetDropShadow(1)
|
||||
specials:SetKerning(16)
|
||||
specials:SetContentAlignment(5)
|
||||
specials:DockMargin(0, padding * 2, 0, padding)
|
||||
specials:Dock(TOP)
|
||||
specials:SizeToContents()
|
||||
|
||||
local specialList = self:Add("ixCreditsSpecials")
|
||||
specialList:DockMargin(0, padding, 0, 0)
|
||||
specialList:Dock(TOP)
|
||||
|
||||
for _, v in ipairs(SPECIALS[1]) do
|
||||
specialList:AddLeft(v[1], v[2])
|
||||
end
|
||||
|
||||
for _, v in ipairs(SPECIALS[2]) do
|
||||
specialList:AddRight(v[1], v[2])
|
||||
end
|
||||
|
||||
specialList:SizeToContents()
|
||||
|
||||
-- less more padding if there's a center column nametag
|
||||
if (IsValid(specialList.center)) then
|
||||
specialList:DockMargin(0, padding, 0, padding)
|
||||
end
|
||||
|
||||
for _, v in ipairs(MISC) do
|
||||
local title = self:Add("DLabel")
|
||||
title:SetFont("ixMenuButtonFontThick")
|
||||
title:SetText(v[1])
|
||||
title:SetContentAlignment(5)
|
||||
title:SizeToContents()
|
||||
title:DockMargin(0, padding, 0, 0)
|
||||
title:Dock(TOP)
|
||||
|
||||
local description = self:Add("DLabel")
|
||||
description:SetFont("ixSmallTitleFont")
|
||||
description:SetText(v[2])
|
||||
description:SetContentAlignment(5)
|
||||
description:SizeToContents()
|
||||
description:Dock(TOP)
|
||||
end
|
||||
|
||||
self:Dock(TOP)
|
||||
self:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
local height = padding
|
||||
|
||||
for _, v in pairs(self:GetChildren()) do
|
||||
local _, top, _, bottom = v:GetDockMargin()
|
||||
height = height + v:GetTall() + top + bottom
|
||||
end
|
||||
|
||||
self:SetTall(height)
|
||||
end
|
||||
|
||||
vgui.Register("ixCredits", PANEL, "Panel")
|
||||
|
||||
hook.Add("PopulateHelpMenu", "ixCredits", function(tabs)
|
||||
tabs["credits"] = function(container)
|
||||
container:Add("ixCredits")
|
||||
end
|
||||
end)
|
||||
271
gamemodes/helix/gamemode/core/derma/cl_dev_icon.lua
Normal file
271
gamemodes/helix/gamemode/core/derma/cl_dev_icon.lua
Normal file
@@ -0,0 +1,271 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--Icon Editor Base and Math Scale Functions from: https://github.com/TeslaCloud/flux-ce/tree/master
|
||||
|
||||
local scaleFactorX = 1 / 1920
|
||||
local scaleFactorY = 1 / 1080
|
||||
|
||||
local function scale(size)
|
||||
return math.floor(size * (ScrH() * scaleFactorY))
|
||||
end
|
||||
|
||||
local function scale_x(size)
|
||||
return math.floor(size * (ScrW() * scaleFactorX))
|
||||
end
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
if (IsValid(ix.gui.dev_icon)) then
|
||||
ix.gui.dev_icon:Remove()
|
||||
end
|
||||
|
||||
ix.gui.dev_icon = self
|
||||
local pW, pH = ScrW() * 0.6, ScrH() * 0.6
|
||||
self:SetSize(pW, pH)
|
||||
self:MakePopup()
|
||||
self:Center()
|
||||
|
||||
local buttonSize = scale(48)
|
||||
|
||||
self.model = vgui.Create("DAdjustableModelPanel", self)
|
||||
self.model:SetSize(pW * 0.5, pH - buttonSize)
|
||||
self.model:Dock(LEFT)
|
||||
self.model:DockMargin(0, 0, 0, buttonSize + scale(8))
|
||||
self.model:SetModel("models/props_borealis/bluebarrel001.mdl")
|
||||
self.model:SetLookAt(Vector(0, 0, 0))
|
||||
|
||||
self.model.LayoutEntity = function() end
|
||||
|
||||
local x = scale_x(4)
|
||||
self.best = vgui.Create("DButton", self)
|
||||
self.best:SetSize(buttonSize, buttonSize)
|
||||
self.best:SetPos(x, pH - buttonSize - scale(4))
|
||||
self.best:SetFont("ixIconsMenuButton")
|
||||
self.best:SetText("b")
|
||||
self.best:SetTooltip(L("iconEditorAlignBest"))
|
||||
|
||||
self.best.DoClick = function()
|
||||
local entity = self.model:GetEntity()
|
||||
local pos = entity:GetPos()
|
||||
local camData = PositionSpawnIcon(entity, pos)
|
||||
|
||||
if (camData) then
|
||||
self.model:SetCamPos(camData.origin)
|
||||
self.model:SetFOV(camData.fov)
|
||||
self.model:SetLookAng(camData.angles)
|
||||
end
|
||||
end
|
||||
|
||||
x = x + buttonSize + scale_x(4)
|
||||
|
||||
self.front = vgui.Create("DButton", self)
|
||||
self.front:SetSize(buttonSize, buttonSize)
|
||||
self.front:SetPos(x, pH - buttonSize - scale(4))
|
||||
self.front:SetFont("ixIconsMenuButton")
|
||||
self.front:SetText("m")
|
||||
self.front:SetTooltip(L("iconEditorAlignFront"))
|
||||
|
||||
self.front.DoClick = function()
|
||||
local entity = self.model:GetEntity()
|
||||
local pos = entity:GetPos()
|
||||
local camPos = pos + Vector(-200, 0, 0)
|
||||
self.model:SetCamPos(camPos)
|
||||
self.model:SetFOV(45)
|
||||
self.model:SetLookAng((camPos * -1):Angle())
|
||||
end
|
||||
|
||||
x = x + buttonSize + scale_x(4)
|
||||
|
||||
self.above = vgui.Create("DButton", self)
|
||||
self.above:SetSize(buttonSize, buttonSize)
|
||||
self.above:SetPos(x, pH - buttonSize - scale(4))
|
||||
self.above:SetFont("ixIconsMenuButton")
|
||||
self.above:SetText("u")
|
||||
self.above:SetTooltip(L("iconEditorAlignAbove"))
|
||||
|
||||
self.above.DoClick = function()
|
||||
local entity = self.model:GetEntity()
|
||||
local pos = entity:GetPos()
|
||||
local camPos = pos + Vector(0, 0, 200)
|
||||
self.model:SetCamPos(camPos)
|
||||
self.model:SetFOV(45)
|
||||
self.model:SetLookAng((camPos * -1):Angle())
|
||||
end
|
||||
|
||||
x = x + buttonSize + scale_x(4)
|
||||
|
||||
self.right = vgui.Create("DButton", self)
|
||||
self.right:SetSize(buttonSize, buttonSize)
|
||||
self.right:SetPos(x, pH - buttonSize - scale(4))
|
||||
self.right:SetFont("ixIconsMenuButton")
|
||||
self.right:SetText("t")
|
||||
self.right:SetTooltip(L("iconEditorAlignRight"))
|
||||
|
||||
self.right.DoClick = function()
|
||||
local entity = self.model:GetEntity()
|
||||
local pos = entity:GetPos()
|
||||
local camPos = pos + Vector(0, 200, 0)
|
||||
self.model:SetCamPos(camPos)
|
||||
self.model:SetFOV(45)
|
||||
self.model:SetLookAng((camPos * -1):Angle())
|
||||
end
|
||||
|
||||
x = x + buttonSize + scale_x(4)
|
||||
|
||||
self.center = vgui.Create("DButton", self)
|
||||
self.center:SetSize(buttonSize, buttonSize)
|
||||
self.center:SetPos(x, pH - buttonSize - scale(4))
|
||||
self.center:SetFont("ixIconsMenuButton")
|
||||
self.center:SetText("T")
|
||||
self.center:SetTooltip(L("iconEditorAlignCenter"))
|
||||
|
||||
self.center.DoClick = function()
|
||||
local entity = self.model:GetEntity()
|
||||
local pos = entity:GetPos()
|
||||
self.model:SetCamPos(pos)
|
||||
self.model:SetFOV(45)
|
||||
self.model:SetLookAng(Angle(0, -180, 0))
|
||||
end
|
||||
|
||||
self.best:DoClick()
|
||||
self.preview = vgui.Create("DPanel", self)
|
||||
self.preview:Dock(FILL)
|
||||
self.preview:DockMargin(scale_x(4), 0, 0, 0)
|
||||
self.preview:DockPadding(scale_x(4), scale(4), scale_x(4), scale(4))
|
||||
|
||||
self.preview.Paint = function(pnl, w, h)
|
||||
draw.RoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 100))
|
||||
end
|
||||
|
||||
self.modelLabel = self.preview:Add("DLabel")
|
||||
self.modelLabel:Dock(TOP)
|
||||
self.modelLabel:SetText("Model")
|
||||
self.modelLabel:SetFont("ixMenuButtonFontSmall")
|
||||
self.modelLabel:DockMargin(4, 4, 4, 4)
|
||||
|
||||
self.modelPath = vgui.Create("ixTextEntry", self.preview)
|
||||
self.modelPath:SetValue(self.model:GetModel())
|
||||
self.modelPath:Dock(TOP)
|
||||
self.modelPath:SetFont("ixMenuButtonFontSmall")
|
||||
self.modelPath:SetPlaceholderText("Model...")
|
||||
|
||||
self.modelPath.OnEnter = function(pnl)
|
||||
local model = pnl:GetValue()
|
||||
|
||||
if (model and model != "") then
|
||||
self.model:SetModel(model)
|
||||
self.item:Rebuild()
|
||||
end
|
||||
end
|
||||
|
||||
self.modelPath.OnLoseFocus = function(pnl)
|
||||
local model = pnl:GetValue()
|
||||
|
||||
if (model and model != "") then
|
||||
self.model:SetModel(model)
|
||||
self.item:Rebuild()
|
||||
end
|
||||
end
|
||||
|
||||
self.width = vgui.Create("ixSettingsRowNumber", self.preview)
|
||||
self.width:Dock(TOP)
|
||||
self.width:SetText(L("iconEditorWidth"))
|
||||
self.width:SetMin(1)
|
||||
self.width:SetMax(24)
|
||||
self.width:SetDecimals(0)
|
||||
self.width:SetValue(1)
|
||||
|
||||
self.width.OnValueChanged = function(pnl, value)
|
||||
self.item:Rebuild()
|
||||
end
|
||||
|
||||
self.height = vgui.Create("ixSettingsRowNumber", self.preview)
|
||||
self.height:Dock(TOP)
|
||||
self.height:SetText(L("iconEditorHeight"))
|
||||
self.height:SetMin(1)
|
||||
self.height:SetMax(24)
|
||||
self.height:SetDecimals(0)
|
||||
self.height:SetValue(1)
|
||||
|
||||
self.height.OnValueChanged = function(pnl, value)
|
||||
self.item:Rebuild()
|
||||
end
|
||||
|
||||
self.itemPanel = vgui.Create("DPanel", self.preview)
|
||||
self.itemPanel:Dock(FILL)
|
||||
|
||||
self.itemPanel.Paint = function(pnl, w, h)
|
||||
draw.RoundedBox(0, 0, 0, w, h, Color(0, 0, 0, 100))
|
||||
end
|
||||
|
||||
self.item = vgui.Create("DModelPanel", self.itemPanel)
|
||||
self.item:SetMouseInputEnabled(false)
|
||||
self.item.LayoutEntity = function() end
|
||||
|
||||
self.item.PaintOver = function(pnl, w, h)
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.DrawOutlinedRect(0, 0, w, h)
|
||||
end
|
||||
|
||||
self.item.Rebuild = function(pnl)
|
||||
local slotSize = 64
|
||||
local padding = scale(2)
|
||||
local slotWidth, slotHeight = math.Round(self.width:GetValue()), math.Round(self.height:GetValue())
|
||||
local w, h = slotWidth * (slotSize + padding) - padding, slotHeight * (slotSize + padding) - padding
|
||||
pnl:SetModel(self.model:GetModel())
|
||||
pnl:SetCamPos(self.model:GetCamPos())
|
||||
pnl:SetFOV(self.model:GetFOV())
|
||||
pnl:SetLookAng(self.model:GetLookAng())
|
||||
pnl:SetSize(w, h)
|
||||
pnl:Center()
|
||||
end
|
||||
|
||||
self.item:Rebuild()
|
||||
|
||||
timer.Create("ix_icon_editor_update", 0.5, 0, function()
|
||||
if IsValid(self) and IsValid(self.model) then
|
||||
self.item:Rebuild()
|
||||
else
|
||||
timer.Remove("ix_icon_editor_update")
|
||||
end
|
||||
end)
|
||||
|
||||
self.copy = vgui.Create("DButton", self)
|
||||
self.copy:SetSize(buttonSize, buttonSize)
|
||||
self.copy:SetPos(pW - buttonSize - scale_x(12), pH - buttonSize - scale(12))
|
||||
self.copy:SetFont("ixIconsMenuButton")
|
||||
self.copy:SetText("}")
|
||||
self.copy:SetTooltip(L("iconEditorCopy"))
|
||||
self.copy.DoClick = function()
|
||||
local camPos = self.model:GetCamPos()
|
||||
local camAng = self.model:GetLookAng()
|
||||
local str = "ITEM.model = \""..self.model:GetModel().."\"\n"
|
||||
.."ITEM.width = "..math.Round(self.width:GetValue()).."\n"
|
||||
.."ITEM.height = "..math.Round(self.height:GetValue()).."\n"
|
||||
.."ITEM.iconCam = {\n"
|
||||
.." pos = Vector("..math.Round(camPos.x, 2)..", "..math.Round(camPos.y, 2)..", "..math.Round(camPos.z, 2).."),\n"
|
||||
.." ang = Angle("..math.Round(camAng.p, 2)..", "..math.Round(camAng.y, 2)..", "..math.Round(camAng.r, 2).."),\n"
|
||||
.." fov = "..math.Round(self.model:GetFOV(), 2).."\n"
|
||||
.."}\n"
|
||||
|
||||
SetClipboardText(str)
|
||||
ix.util.Notify(L("iconEditorCopied"))
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ix_icon_editor", PANEL, "DFrame")
|
||||
|
||||
concommand.Add("ix_dev_icon", function()
|
||||
if (LocalPlayer():IsAdmin()) then
|
||||
vgui.Create("ix_icon_editor")
|
||||
end
|
||||
end)
|
||||
287
gamemodes/helix/gamemode/core/derma/cl_entitymenu.lua
Normal file
287
gamemodes/helix/gamemode/core/derma/cl_entitymenu.lua
Normal file
@@ -0,0 +1,287 @@
|
||||
--[[
|
||||
| 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 animationTime = 1
|
||||
local padding = 32
|
||||
|
||||
-- entity menu button
|
||||
DEFINE_BASECLASS("ixMenuButton")
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "callback", "Callback")
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetTall(ScrH() * 0.1)
|
||||
self:Dock(TOP)
|
||||
end
|
||||
|
||||
function PANEL:DoClick()
|
||||
local bStatus = true
|
||||
local parent = ix.menu.panel
|
||||
local entity = parent:GetEntity()
|
||||
|
||||
if (parent.bClosing) then
|
||||
return
|
||||
end
|
||||
|
||||
if (isfunction(self.callback)) then
|
||||
bStatus = self.callback()
|
||||
end
|
||||
|
||||
if (bStatus != false) then
|
||||
ix.menu.NetworkChoice(entity, self.originalText, bStatus)
|
||||
end
|
||||
|
||||
parent:Remove()
|
||||
end
|
||||
|
||||
function PANEL:SetText(text)
|
||||
self.originalText = text
|
||||
BaseClass.SetText(self, text)
|
||||
end
|
||||
|
||||
vgui.Register("ixEntityMenuButton", PANEL, "ixMenuButton")
|
||||
|
||||
-- entity menu list
|
||||
DEFINE_BASECLASS("EditablePanel")
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.list = {}
|
||||
end
|
||||
|
||||
function PANEL:AddOption(text, callback)
|
||||
local panel = self:Add("ixEntityMenuButton")
|
||||
panel:SetText(text)
|
||||
panel:SetCallback(callback)
|
||||
panel:Dock(TOP)
|
||||
|
||||
if (self.bPaintedManually) then
|
||||
panel:SetPaintedManually(true)
|
||||
end
|
||||
|
||||
self.list[#self.list + 1] = panel
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
local height = 0
|
||||
|
||||
for i = 1, #self.list do
|
||||
height = height + self.list[i]:GetTall()
|
||||
end
|
||||
|
||||
self:SetSize(ScrW() * 0.5 - padding * 2, height)
|
||||
end
|
||||
|
||||
function PANEL:Center()
|
||||
local parent = self:GetParent()
|
||||
|
||||
self:SetPos(
|
||||
ScrW() * 0.5 + padding,
|
||||
parent:GetTall() * 0.5 - self:GetTall() * 0.5
|
||||
)
|
||||
end
|
||||
|
||||
function PANEL:SetPaintedManually(bValue)
|
||||
if (bValue) then
|
||||
for i = 1, #self.list do
|
||||
self.list[i]:SetPaintedManually(true)
|
||||
end
|
||||
|
||||
self.bPaintedManually = true
|
||||
end
|
||||
|
||||
BaseClass.SetPaintedManually(self, bValue)
|
||||
end
|
||||
|
||||
function PANEL:PaintManual()
|
||||
BaseClass.PaintManual(self)
|
||||
local list = self.list
|
||||
|
||||
for i = 1, #list do
|
||||
list[i]:PaintManual()
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixEntityMenuList", PANEL, "EditablePanel")
|
||||
|
||||
-- entity menu
|
||||
DEFINE_BASECLASS("EditablePanel")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "entity", "Entity")
|
||||
AccessorFunc(PANEL, "bClosing", "IsClosing", FORCE_BOOL)
|
||||
AccessorFunc(PANEL, "desiredHeight", "DesiredHeight", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
if (IsValid(ix.menu.panel)) then
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
-- close entity tooltip if it's open
|
||||
if (IsValid(ix.gui.entityInfo)) then
|
||||
ix.gui.entityInfo:Remove()
|
||||
end
|
||||
|
||||
ix.menu.panel = self
|
||||
|
||||
self:SetSize(ScrW(), ScrH())
|
||||
self:SetPos(0, 0)
|
||||
|
||||
self.list = self:Add("ixEntityMenuList")
|
||||
self.list:SetPaintedManually(true)
|
||||
|
||||
self.desiredHeight = 0
|
||||
self.blur = 0
|
||||
self.alpha = 1
|
||||
self.bClosing = false
|
||||
self.lastPosition = vector_origin
|
||||
|
||||
self:CreateAnimation(animationTime, {
|
||||
target = {blur = 1},
|
||||
easing = "outQuint"
|
||||
})
|
||||
|
||||
self:MakePopup()
|
||||
end
|
||||
|
||||
function PANEL:SetOptions(options)
|
||||
for k, v in pairs(options) do
|
||||
self.list:AddOption(k, v)
|
||||
end
|
||||
|
||||
self.list:SizeToContents()
|
||||
self.list:Center()
|
||||
end
|
||||
|
||||
function PANEL:GetApproximateScreenHeight(entity, distanceSqr)
|
||||
return IsValid(entity) and
|
||||
(entity:BoundingRadius() * (entity:IsPlayer() and 1.5 or 1) or 0) / math.sqrt(distanceSqr) * self:GetTall() or 0
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
local entity = self.entity
|
||||
local distance = 0
|
||||
|
||||
if (IsValid(entity)) then
|
||||
local position = entity:GetPos()
|
||||
distance = LocalPlayer():GetShootPos():DistToSqr(position)
|
||||
|
||||
if (distance > 65536) then
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
self.lastPosition = position
|
||||
end
|
||||
|
||||
self.desiredHeight = math.max(self.list:GetTall() + padding * 2, self:GetApproximateScreenHeight(entity, distance))
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height) -- luacheck: ignore 312
|
||||
local selfHalf = self:GetTall() * 0.5
|
||||
local entity = self.entity
|
||||
|
||||
height = self.desiredHeight + padding * 2
|
||||
width = self.blur * width
|
||||
|
||||
local y = selfHalf - height * 0.5
|
||||
|
||||
DisableClipping(true) -- for cheap blur
|
||||
render.SetScissorRect(0, y, width, y + height, true)
|
||||
if (IsValid(entity)) then
|
||||
cam.Start3D()
|
||||
ix.util.ResetStencilValues()
|
||||
render.SetStencilEnable(true)
|
||||
cam.IgnoreZ(true)
|
||||
render.SetStencilWriteMask(29)
|
||||
render.SetStencilTestMask(29)
|
||||
render.SetStencilReferenceValue(29)
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_ALWAYS)
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilZFailOperation(STENCIL_KEEP)
|
||||
|
||||
entity:DrawModel()
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_NOTEQUAL)
|
||||
render.SetStencilPassOperation(STENCIL_KEEP)
|
||||
|
||||
cam.Start2D()
|
||||
ix.util.DrawBlur(self, 10)
|
||||
cam.End2D()
|
||||
cam.IgnoreZ(false)
|
||||
render.SetStencilEnable(false)
|
||||
cam.End3D()
|
||||
else
|
||||
ix.util.DrawBlur(self, 10)
|
||||
end
|
||||
render.SetScissorRect(0, 0, 0, 0, false)
|
||||
DisableClipping(false)
|
||||
|
||||
-- scissor again because 3d rendering messes with the clipping apparently?
|
||||
render.SetScissorRect(0, y, width, y + height, true)
|
||||
surface.SetDrawColor(ix.config.Get("color"))
|
||||
surface.DrawRect(ScrW() * 0.5, y + padding, 1, height - padding * 2)
|
||||
|
||||
self.list:PaintManual()
|
||||
render.SetScissorRect(0, 0, 0, 0, false)
|
||||
end
|
||||
|
||||
function PANEL:GetOverviewInfo(origin, angles)
|
||||
local entity = self.entity
|
||||
|
||||
if (IsValid(entity)) then
|
||||
local radius = entity:BoundingRadius() * (entity:IsPlayer() and 0.5 or 1)
|
||||
local center = entity:LocalToWorld(entity:OBBCenter()) + LocalPlayer():GetRight() * radius
|
||||
|
||||
return LerpAngle(self.bClosing and self.alpha or self.blur, angles, (center - origin):Angle())
|
||||
end
|
||||
|
||||
return angles
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed(code)
|
||||
if (code == MOUSE_LEFT) then
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Remove()
|
||||
if (self.bClosing) then
|
||||
return
|
||||
end
|
||||
|
||||
self.bClosing = true
|
||||
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
gui.EnableScreenClicker(false)
|
||||
|
||||
self:CreateAnimation(animationTime * 0.5, {
|
||||
target = {alpha = 0},
|
||||
index = 2,
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.alpha * 255)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
ix.menu.panel = nil
|
||||
BaseClass.Remove(self)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
vgui.Register("ixEntityMenu", PANEL, "EditablePanel")
|
||||
933
gamemodes/helix/gamemode/core/derma/cl_generic.lua
Normal file
933
gamemodes/helix/gamemode/core/derma/cl_generic.lua
Normal file
@@ -0,0 +1,933 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- generic panels that are applicable anywhere
|
||||
|
||||
-- used for prominent text entries
|
||||
DEFINE_BASECLASS("DTextEntry")
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetPaintBackground(false)
|
||||
self:SetTextColor(color_white)
|
||||
|
||||
self.backgroundColor = Color(255, 255, 255, 25)
|
||||
end
|
||||
|
||||
function PANEL:SetFont(font)
|
||||
surface.SetFont(font)
|
||||
local _, height = surface.GetTextSize("W@")
|
||||
|
||||
self:SetTall(height)
|
||||
BaseClass.SetFont(self, font)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, self.backgroundColor)
|
||||
BaseClass.Paint(self, width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixTextEntry", PANEL, "DTextEntry")
|
||||
|
||||
-- similar to a frame, but is mainly used for grouping panels together in a list
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "text", "Text", FORCE_STRING)
|
||||
AccessorFunc(PANEL, "color", "Color")
|
||||
|
||||
function PANEL:Init()
|
||||
self.text = ""
|
||||
self.paddingTop = 32
|
||||
|
||||
local skin = self:GetSkin()
|
||||
|
||||
if (skin and skin.fontCategoryBlur) then
|
||||
surface.SetFont(skin.fontCategoryBlur)
|
||||
self.paddingTop = select(2, surface.GetTextSize("W@")) + 6
|
||||
end
|
||||
|
||||
self:DockPadding(1, self.paddingTop, 1, 1)
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
local height = self.paddingTop + 1
|
||||
|
||||
for _, v in ipairs(self:GetChildren()) do
|
||||
if (IsValid(v) and v:IsVisible()) then
|
||||
local _, top, _, bottom = v:GetDockMargin()
|
||||
|
||||
height = height + v:GetTall() + top + bottom
|
||||
end
|
||||
end
|
||||
|
||||
self:SetTall(height)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("PaintCategoryPanel", self, self.text, self.color)
|
||||
end
|
||||
|
||||
vgui.Register("ixCategoryPanel", PANEL, "EditablePanel")
|
||||
|
||||
-- segmented progress bar
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "font", "Font", FORCE_STRING)
|
||||
AccessorFunc(PANEL, "barColor", "BarColor")
|
||||
AccessorFunc(PANEL, "textColor", "TextColor")
|
||||
AccessorFunc(PANEL, "progress", "Progress", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "easingType", "EasingType", FORCE_STRING)
|
||||
|
||||
function PANEL:Init()
|
||||
self.segments = {}
|
||||
self.padding = ScrH() * 0.01
|
||||
self.fraction = 0
|
||||
self.animationTime = 0.5
|
||||
self.easingType = "outQuint"
|
||||
self.progress = 0
|
||||
end
|
||||
|
||||
function PANEL:AddSegment(text)
|
||||
local id = #self.segments + 1
|
||||
|
||||
if (text:sub(1, 1) == "@") then
|
||||
text = L(text:sub(2))
|
||||
end
|
||||
|
||||
self.segments[id] = text
|
||||
return id
|
||||
end
|
||||
|
||||
function PANEL:AddSegments(...)
|
||||
local segments = {...}
|
||||
|
||||
for i = 1, #segments do
|
||||
self:AddSegment(segments[i])
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:GetSegments()
|
||||
return self.segments
|
||||
end
|
||||
|
||||
function PANEL:SetProgress(segment)
|
||||
self.progress = math.Clamp(segment, 0, #self.segments)
|
||||
|
||||
self:CreateAnimation(self.animationTime, {
|
||||
target = {fraction = self.progress / #self.segments},
|
||||
easing = self.easingType
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:IncrementProgress(amount)
|
||||
self:SetProgress(self.progress + (amount or 1))
|
||||
end
|
||||
|
||||
function PANEL:DecrementProgress(amount)
|
||||
self:SetProgress(self.progress - (amount or 1))
|
||||
end
|
||||
|
||||
function PANEL:GetFraction()
|
||||
return self.fraction
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
self:SetTall(draw.GetFontHeight(self.font or self:GetSkin().fontSegmentedProgress) + self.padding)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("PaintSegmentedProgressBackground", self, width, height)
|
||||
|
||||
if (#self.segments > 0) then
|
||||
derma.SkinFunc("PaintSegmentedProgress", self, width, height)
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixSegmentedProgress", PANEL, "Panel")
|
||||
|
||||
-- list of labelled information
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "labelColor", "LabelColor")
|
||||
AccessorFunc(PANEL, "textColor", "TextColor")
|
||||
AccessorFunc(PANEL, "list", "List")
|
||||
AccessorFunc(PANEL, "minWidth", "MinimumWidth", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self.label = self:Add("DLabel")
|
||||
self.label:SetFont("ixMediumFont")
|
||||
self.label:SetExpensiveShadow(1)
|
||||
self.label:SetTextColor(color_white)
|
||||
self.label:SetText("Label")
|
||||
self.label:SetContentAlignment(5)
|
||||
self.label:Dock(LEFT)
|
||||
self.label:DockMargin(0, 0, 4, 0)
|
||||
self.label:SizeToContents()
|
||||
self.label.Paint = function(this, width, height)
|
||||
derma.SkinFunc("PaintListRow", this, width, height)
|
||||
end
|
||||
|
||||
self.text = self:Add("DLabel")
|
||||
self.text:SetFont("ixMediumLightFont")
|
||||
self.text:SetTextColor(color_white)
|
||||
self.text:SetText("Text")
|
||||
self.text:SetTextInset(8, 0)
|
||||
self.text:Dock(FILL)
|
||||
self.text:DockMargin(4, 0, 0, 0)
|
||||
self.text:SizeToContents()
|
||||
self.text.Paint = function(this, width, height)
|
||||
derma.SkinFunc("PaintListRow", this, width, height)
|
||||
end
|
||||
|
||||
self:DockMargin(0, 0, 0, 8)
|
||||
|
||||
self.list = {}
|
||||
self.minWidth = 100
|
||||
end
|
||||
|
||||
function PANEL:SetRightPanel(panel)
|
||||
self.text:Remove()
|
||||
|
||||
self.text = self:Add(panel)
|
||||
self.text:Dock(FILL)
|
||||
self.text:DockMargin(8, 4, 4, 4)
|
||||
self.text:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:SetList(list, bNoAdd)
|
||||
if (!bNoAdd) then
|
||||
list[#list + 1] = self
|
||||
end
|
||||
|
||||
self.list = list
|
||||
end
|
||||
|
||||
function PANEL:UpdateLabelWidths()
|
||||
local maxWidth = self.label:GetWide()
|
||||
|
||||
for i = 1, #self.list do
|
||||
maxWidth = math.max(self.list[i]:GetLabelWidth(), maxWidth)
|
||||
end
|
||||
|
||||
maxWidth = math.max(self.minWidth, maxWidth)
|
||||
|
||||
for i = 1, #self.list do
|
||||
self.list[i]:SetLabelWidth(maxWidth)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetLabelColor(color)
|
||||
self.label:SetTextColor(color)
|
||||
end
|
||||
|
||||
function PANEL:SetTextColor(color)
|
||||
self.text:SetTextColor(color)
|
||||
end
|
||||
|
||||
function PANEL:SetLabelText(text)
|
||||
self.label:SetText(text)
|
||||
self.label:SizeToContents()
|
||||
|
||||
self:UpdateLabelWidths()
|
||||
end
|
||||
|
||||
function PANEL:SetText(text)
|
||||
self.text:SetText(text)
|
||||
self.text:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:SetLabelWidth(width)
|
||||
self.label:SetWide(width)
|
||||
end
|
||||
|
||||
function PANEL:GetLabelWidth(bWithoutMargin)
|
||||
if (!bWithoutMargin) then
|
||||
return self.label:GetWide()
|
||||
end
|
||||
|
||||
local left, _, right, _ = self.label:GetDockMargin()
|
||||
return self.label:GetWide() + left + right
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
self:SetTall(math.max(self.label:GetTall(), self.text:GetTall()) + 8)
|
||||
end
|
||||
|
||||
vgui.Register("ixListRow", PANEL, "Panel")
|
||||
|
||||
-- alternative checkbox
|
||||
DEFINE_BASECLASS("EditablePanel")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "enabledText", "EnabledText", FORCE_STRING)
|
||||
AccessorFunc(PANEL, "disabledText", "DisabledText", FORCE_STRING)
|
||||
AccessorFunc(PANEL, "font", "Font", FORCE_STRING)
|
||||
AccessorFunc(PANEL, "bChecked", "Checked", FORCE_BOOL)
|
||||
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "labelPadding", "LabelPadding", FORCE_NUMBER)
|
||||
|
||||
PANEL.GetValue = PANEL.GetChecked
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetMouseInputEnabled(true)
|
||||
self:SetCursor("hand")
|
||||
|
||||
self.enabledText = L("yes"):utf8upper()
|
||||
self.disabledText = L("no"):utf8upper()
|
||||
self.font = "ixMenuButtonFont"
|
||||
self.animationTime = 0.5
|
||||
self.bChecked = false
|
||||
self.labelPadding = 8
|
||||
self.animationOffset = 0
|
||||
|
||||
self:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
BaseClass.SizeToContents(self)
|
||||
|
||||
surface.SetFont(self.font)
|
||||
self:SetWide(math.max(surface.GetTextSize(self.enabledText), surface.GetTextSize(self.disabledText)) + self.labelPadding)
|
||||
end
|
||||
|
||||
-- can be overidden to change audio params
|
||||
function PANEL:GetAudioFeedback()
|
||||
return "weapons/ar2/ar2_empty.wav", 75, self.bChecked and 150 or 125, 0.25
|
||||
end
|
||||
|
||||
function PANEL:EmitFeedback()
|
||||
LocalPlayer():EmitSound(self:GetAudioFeedback())
|
||||
end
|
||||
|
||||
function PANEL:SetChecked(bChecked, bInstant)
|
||||
self.bChecked = tobool(bChecked)
|
||||
|
||||
self:CreateAnimation(bInstant and 0 or self.animationTime, {
|
||||
index = 1,
|
||||
target = {
|
||||
animationOffset = bChecked and 1 or 0
|
||||
},
|
||||
easing = "outElastic"
|
||||
})
|
||||
|
||||
if (!bInstant) then
|
||||
self:EmitFeedback()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed(code)
|
||||
if (code == MOUSE_LEFT) then
|
||||
self:SetChecked(!self.bChecked)
|
||||
self:DoClick()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:DoClick()
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
|
||||
local offset = self.animationOffset
|
||||
surface.SetFont(self.font)
|
||||
|
||||
local text = self.disabledText
|
||||
local textWidth, textHeight = surface.GetTextSize(text)
|
||||
local y = offset * -textHeight
|
||||
|
||||
surface.SetTextColor(250, 60, 60, 255)
|
||||
surface.SetTextPos(width * 0.5 - textWidth * 0.5, y + height * 0.5 - textHeight * 0.5)
|
||||
surface.DrawText(text)
|
||||
|
||||
text = self.enabledText
|
||||
y = y + textHeight
|
||||
textWidth, textHeight = surface.GetTextSize(text)
|
||||
|
||||
surface.SetTextColor(30, 250, 30, 255)
|
||||
surface.SetTextPos(width * 0.5 - textWidth * 0.5, y + height * 0.5 - textHeight * 0.5)
|
||||
surface.DrawText(text)
|
||||
end
|
||||
|
||||
vgui.Register("ixCheckBox", PANEL, "EditablePanel")
|
||||
|
||||
-- alternative num slider
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "labelPadding", "LabelPadding", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self.labelPadding = 8
|
||||
|
||||
surface.SetFont("ixMenuButtonFont")
|
||||
local totalWidth = surface.GetTextSize("999") -- start off with 3 digit width
|
||||
|
||||
self.label = self:Add("DLabel")
|
||||
self.label:Dock(RIGHT)
|
||||
self.label:SetWide(totalWidth + self.labelPadding)
|
||||
self.label:SetContentAlignment(5)
|
||||
self.label:SetFont("ixMenuButtonFont")
|
||||
self.label.Paint = function(panel, width, height)
|
||||
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
self.label.SizeToContents = function(panel)
|
||||
surface.SetFont(panel:GetFont())
|
||||
local textWidth = surface.GetTextSize(panel:GetText())
|
||||
|
||||
if (textWidth > totalWidth) then
|
||||
panel:SetWide(textWidth + self.labelPadding)
|
||||
elseif (panel:GetWide() > totalWidth + self.labelPadding) then
|
||||
panel:SetWide(totalWidth + self.labelPadding)
|
||||
end
|
||||
end
|
||||
|
||||
self.slider = self:Add("ixSlider")
|
||||
self.slider:Dock(FILL)
|
||||
self.slider:DockMargin(0, 0, 4, 0)
|
||||
self.slider.OnValueChanged = function(panel)
|
||||
self:OnValueChanged()
|
||||
end
|
||||
self.slider.OnValueUpdated = function(panel)
|
||||
self.label:SetText(string.format("%0." .. tostring(panel:GetDecimals()) .. "f", tostring(panel:GetValue())))
|
||||
self.label:SizeToContents()
|
||||
|
||||
self:OnValueUpdated()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:GetLabel()
|
||||
return self.label
|
||||
end
|
||||
|
||||
function PANEL:GetSlider()
|
||||
return self.slider
|
||||
end
|
||||
|
||||
function PANEL:SetValue(value, bNoNotify)
|
||||
value = tonumber(value) or self.slider:GetMin()
|
||||
|
||||
self.slider:SetValue(value, bNoNotify)
|
||||
self.label:SetText(string.format("%0." .. tostring(self:GetDecimals()) .. "f", tostring(self.slider:GetValue())))
|
||||
self.label:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:GetValue()
|
||||
return self.slider:GetValue()
|
||||
end
|
||||
|
||||
function PANEL:GetFraction()
|
||||
return self.slider:GetFraction()
|
||||
end
|
||||
|
||||
function PANEL:GetVisualFraction()
|
||||
return self.slider:GetVisualFraction()
|
||||
end
|
||||
|
||||
function PANEL:SetMin(value)
|
||||
self.slider:SetMin(value)
|
||||
end
|
||||
|
||||
function PANEL:SetMax(value)
|
||||
self.slider:SetMax(value)
|
||||
end
|
||||
|
||||
function PANEL:GetMin()
|
||||
return self.slider:GetMin()
|
||||
end
|
||||
|
||||
function PANEL:GetMax()
|
||||
return self.slider:GetMax()
|
||||
end
|
||||
|
||||
function PANEL:SetDecimals(value)
|
||||
self.slider:SetDecimals(value)
|
||||
end
|
||||
|
||||
function PANEL:GetDecimals()
|
||||
return self.slider:GetDecimals()
|
||||
end
|
||||
|
||||
-- called when changed by user
|
||||
function PANEL:OnValueChanged()
|
||||
end
|
||||
|
||||
-- called when changed while dragging bar
|
||||
function PANEL:OnValueUpdated()
|
||||
end
|
||||
|
||||
vgui.Register("ixNumSlider", PANEL, "Panel")
|
||||
|
||||
-- alternative slider
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "bDragging", "Dragging", FORCE_BOOL)
|
||||
AccessorFunc(PANEL, "min", "Min", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "max", "Max", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "decimals", "Decimals", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self.min = 0
|
||||
self.max = 10
|
||||
self.value = 0
|
||||
self.visualValue = 0
|
||||
self.decimals = 0
|
||||
|
||||
self:SetCursor("hand")
|
||||
end
|
||||
|
||||
function PANEL:SetValue(value, bNoNotify)
|
||||
self.value = math.Clamp(math.Round(tonumber(value) or self.min, self.decimals), self.min, self.max)
|
||||
self:ValueUpdated(bNoNotify)
|
||||
|
||||
if (!bNoNotify) then
|
||||
self:OnValueChanged()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:GetValue()
|
||||
return self.value
|
||||
end
|
||||
|
||||
function PANEL:GetFraction()
|
||||
return math.Remap(self.value, self.min, self.max, 0, 1)
|
||||
end
|
||||
|
||||
function PANEL:GetVisualFraction()
|
||||
return math.Remap(self.visualValue, self.min, self.max, 0, 1)
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed(key)
|
||||
if (key == MOUSE_LEFT) then
|
||||
self.bDragging = true
|
||||
self:MouseCapture(true)
|
||||
|
||||
self:OnCursorMoved(self:CursorPos())
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnMouseReleased(key)
|
||||
if (self.bDragging) then
|
||||
self:OnValueChanged()
|
||||
end
|
||||
|
||||
self.bDragging = false
|
||||
self:MouseCapture(false)
|
||||
end
|
||||
|
||||
function PANEL:OnCursorMoved(x, y)
|
||||
if (!self.bDragging) then
|
||||
return
|
||||
end
|
||||
|
||||
x = math.Clamp(x, 0, self:GetWide())
|
||||
local oldValue = self.value
|
||||
|
||||
self.value = math.Clamp(math.Round(
|
||||
math.Remap(x / self:GetWide(), 0, 1, self.min, self.max), self.decimals
|
||||
), self.min, self.max)
|
||||
|
||||
self:CreateAnimation(0.5, {
|
||||
index = 1,
|
||||
target = {visualValue = self.value},
|
||||
easing = "outQuint"
|
||||
})
|
||||
|
||||
if (self.value != oldValue) then
|
||||
self:ValueUpdated()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnValueChanged()
|
||||
end
|
||||
|
||||
function PANEL:ValueUpdated(bNoNotify)
|
||||
self:CreateAnimation(bNoNotify and 0 or 0.5, {
|
||||
index = 1,
|
||||
target = {visualValue = self.value},
|
||||
easing = "outQuint"
|
||||
})
|
||||
|
||||
if (!bNoNotify) then
|
||||
self:OnValueUpdated()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnValueUpdated()
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("PaintHelixSlider", self, width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixSlider", PANEL, "EditablePanel")
|
||||
|
||||
--- Alternative to DLabel that adds extra functionality.
|
||||
-- This panel is meant for drawing single-line text. It can add extra kerning (spaces between letters), and it can forcefully
|
||||
-- scale the text down to fit the current width, without cutting off any letters. Text scaling is most useful when docking this
|
||||
-- this panel without knowing what the width could be. For example, text scaling is used for the character name in the character
|
||||
-- status menu.
|
||||
-- local label = vgui.Create("ixLabel")
|
||||
-- label:SetText("hello world")
|
||||
-- label:SetFont("ixMenuButtonHugeFont")
|
||||
-- label:SetContentAlignment(5)
|
||||
-- label:SetTextColor(Color(255, 255, 255, 255))
|
||||
-- label:SetBackgroundColor(Color(200, 30, 30, 255))
|
||||
-- label:SetPadding(8)
|
||||
-- label:SetScaleWidth(true)
|
||||
-- label:SizeToContents()
|
||||
-- @panel ixLabel
|
||||
PANEL = {}
|
||||
|
||||
--- Sets the text for this label to display.
|
||||
-- @realm client
|
||||
-- @string text Text to display
|
||||
-- @function SetText
|
||||
|
||||
--- Returns the current text for this panel.
|
||||
-- @realm client
|
||||
-- @treturn string Current text
|
||||
-- @function GetText
|
||||
AccessorFunc(PANEL, "text", "Text", FORCE_STRING)
|
||||
|
||||
--- Sets the color of the text to use when drawing.
|
||||
-- @realm client
|
||||
-- @color color New color to use
|
||||
-- @function SetTextColor
|
||||
|
||||
--- Returns the current text color for this panel.
|
||||
-- @realm client
|
||||
-- @treturn color Current text color
|
||||
-- @function GetTextColor
|
||||
AccessorFunc(PANEL, "color", "TextColor")
|
||||
|
||||
--- Sets the color of the background to draw behind the text.
|
||||
-- @realm client
|
||||
-- @color color New color to use
|
||||
-- @function SetBackgroundColor
|
||||
|
||||
--- Returns the current background color for this panel.
|
||||
-- @realm client
|
||||
-- @treturn color Current background color
|
||||
-- @function GetBackgroundColor
|
||||
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
|
||||
|
||||
--- Sets the spacing between each character of the text in pixels. Set to `0` to disable. Kerning is disabled by default.
|
||||
-- @realm client
|
||||
-- @number kerning How far apart to draw each letter
|
||||
-- @function SetKerning
|
||||
|
||||
--- Returns the current kerning for this panel.
|
||||
-- @realm client
|
||||
-- @treturn number Current kerning
|
||||
-- @function GetKerning
|
||||
AccessorFunc(PANEL, "kerning", "Kerning", FORCE_NUMBER)
|
||||
|
||||
--- Sets the font used to draw the text.
|
||||
-- @realm client
|
||||
-- @string font Name of the font to use
|
||||
-- @function SetFont
|
||||
|
||||
--- Returns the current font for this panel.
|
||||
-- @realm client
|
||||
-- @treturn string Name of current font
|
||||
-- @function GetFont
|
||||
AccessorFunc(PANEL, "font", "Font", FORCE_STRING)
|
||||
|
||||
--- Changes how the text is aligned when drawing. Valid content alignment values include numbers `1` through `9`. Each number's
|
||||
-- corresponding alignment is based on its position on a numpad. For example, `1` is bottom-left, `5` is centered, `9` is
|
||||
-- top-right, etc.
|
||||
-- @realm client
|
||||
-- @number alignment Alignment to use
|
||||
-- @function SetContentAlignment
|
||||
|
||||
--- Returns the current content alignment for this panel.
|
||||
-- @realm client
|
||||
-- @treturn number Current content alignment
|
||||
-- @function GetContentAlignment
|
||||
AccessorFunc(PANEL, "contentAlignment", "ContentAlignment", FORCE_NUMBER)
|
||||
|
||||
--- Whether or not to scale the width of the text down to fit the width of this panel, if needed.
|
||||
-- @realm client
|
||||
-- @bool bScale Whether or not to scale
|
||||
-- @function SetScaleWidth
|
||||
|
||||
--- Returns whether or not this panel will scale its text down to fit its width.
|
||||
-- @realm client
|
||||
-- @treturn bool Whether or not this panel will scale its text
|
||||
-- @function GetScaleWidth
|
||||
AccessorFunc(PANEL, "bScaleWidth", "ScaleWidth", FORCE_BOOL)
|
||||
|
||||
--- How much spacing to use around the text when its drawn. This uses uniform padding on the top, left, right, and bottom of
|
||||
-- this panel.
|
||||
-- @realm client
|
||||
-- @number padding Padding to use
|
||||
-- @function SetPadding
|
||||
|
||||
--- Returns how much padding this panel has around its text.
|
||||
-- @realm client
|
||||
-- @treturn number Current padding
|
||||
-- @function GetPadding
|
||||
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self.text = ""
|
||||
self.color = color_white
|
||||
self.backgroundColor = Color(255, 255, 255, 0)
|
||||
self.kerning = 0
|
||||
self.font = "DermaDefault"
|
||||
self.scaledFont = "DermaDefault"
|
||||
self.contentAlignment = 5
|
||||
self.bScaleWidth = false
|
||||
self.padding = 0
|
||||
|
||||
self.shadowDistance = 0
|
||||
self.bCurrentlyScaling = false
|
||||
end
|
||||
|
||||
function PANEL:SetText(text)
|
||||
self.text = tostring(text)
|
||||
end
|
||||
|
||||
function PANEL:SetFont(font)
|
||||
self.font = font
|
||||
self.scaledFont = font
|
||||
end
|
||||
|
||||
--- Sets the drop shadow to draw behind the text.
|
||||
-- @realm client
|
||||
-- @number distance How far away to draw the shadow in pixels. Set to `0` to disable
|
||||
-- @color[opt] color Color of the shadow. Defaults to a dimmed version of the text color
|
||||
function PANEL:SetDropShadow(distance, color)
|
||||
self.shadowDistance = distance or 1
|
||||
self.shadowColor = color or ix.util.DimColor(self.color, 0.5)
|
||||
end
|
||||
|
||||
PANEL.SetExpensiveShadow = PANEL.SetDropShadow -- aliasing for easier conversion from DLabels
|
||||
|
||||
--- Returns the X and Y location of the text taking into account the text alignment and padding.
|
||||
-- @realm client
|
||||
-- @internal
|
||||
-- @number width Width of the panel
|
||||
-- @number height Height of the panel
|
||||
-- @number textWidth Width of the text
|
||||
-- @number textHeight Height of the text
|
||||
-- @treturn number X location to draw the text
|
||||
-- @treturn number Y location to draw the text
|
||||
function PANEL:CalculateAlignment(width, height, textWidth, textHeight)
|
||||
local alignment = self.contentAlignment
|
||||
local x, y
|
||||
|
||||
if (self.bCurrentlyScaling) then
|
||||
-- if the text is currently being scaled down, then it's always centered
|
||||
x = width * 0.5 - textWidth * 0.5
|
||||
else
|
||||
-- x alignment
|
||||
if (alignment == 7 or alignment == 4 or alignment == 1) then
|
||||
-- left
|
||||
x = self.padding
|
||||
elseif (alignment == 8 or alignment == 5 or alignment == 2) then
|
||||
-- center
|
||||
x = width * 0.5 - textWidth * 0.5
|
||||
elseif (alignment == 9 or alignment == 6 or alignment == 3) then
|
||||
x = width - textWidth - self.padding
|
||||
end
|
||||
end
|
||||
|
||||
-- y alignment
|
||||
if (alignment <= 3) then
|
||||
-- bottom
|
||||
y = height - textHeight - self.padding
|
||||
elseif (alignment <= 6) then
|
||||
-- center
|
||||
y = height * 0.5 - textHeight * 0.5
|
||||
else
|
||||
-- top
|
||||
y = self.padding
|
||||
end
|
||||
|
||||
return x, y
|
||||
end
|
||||
|
||||
--- Draws the current text with the current kerning.
|
||||
-- @realm client
|
||||
-- @internal
|
||||
-- @number width Width of the panel
|
||||
-- @number height Height of the panel
|
||||
function PANEL:DrawKernedText(width, height)
|
||||
local contentWidth, contentHeight = self:GetContentSize()
|
||||
local x, y = self:CalculateAlignment(width, height, contentWidth, contentHeight)
|
||||
|
||||
for i = 1, self.text:utf8len() do
|
||||
local character = self.text:utf8sub(i, i)
|
||||
local textWidth, _ = surface.GetTextSize(character)
|
||||
local kerning = i == 1 and 0 or self.kerning
|
||||
local shadowDistance = self.shadowDistance
|
||||
|
||||
-- shadow
|
||||
if (self.shadowDistance > 0) then
|
||||
surface.SetTextColor(self.shadowColor)
|
||||
surface.SetTextPos(x + kerning + shadowDistance, y + shadowDistance)
|
||||
surface.DrawText(character)
|
||||
end
|
||||
|
||||
-- character
|
||||
surface.SetTextColor(self.color)
|
||||
surface.SetTextPos(x + kerning, y)
|
||||
surface.DrawText(character)
|
||||
|
||||
x = x + textWidth + kerning
|
||||
end
|
||||
end
|
||||
|
||||
--- Draws the current text.
|
||||
-- @realm client
|
||||
-- @internal
|
||||
-- @number width Width of the panel
|
||||
-- @number height Height of the panel
|
||||
function PANEL:DrawText(width, height)
|
||||
local textWidth, textHeight = surface.GetTextSize(self.text)
|
||||
local x, y = self:CalculateAlignment(width, height, textWidth, textHeight)
|
||||
|
||||
-- shadow
|
||||
if (self.shadowDistance > 0) then
|
||||
surface.SetTextColor(self.shadowColor)
|
||||
surface.SetTextPos(x + self.shadowDistance, y + self.shadowDistance)
|
||||
surface.DrawText(self.text)
|
||||
end
|
||||
|
||||
-- text
|
||||
surface.SetTextColor(self.color)
|
||||
surface.SetTextPos(x, y)
|
||||
surface.DrawText(self.text)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
surface.SetFont(self.font)
|
||||
surface.SetDrawColor(self.backgroundColor)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
|
||||
if (self.bScaleWidth) then
|
||||
local contentWidth, contentHeight = self:GetContentSize()
|
||||
|
||||
if (contentWidth > (width - self.padding * 2)) then
|
||||
local x, y = self:LocalToScreen(self:GetPos())
|
||||
local scale = width / (contentWidth + self.padding * 2)
|
||||
local translation = Vector(x + width * 0.5, y - contentHeight * 0.5 + self.padding, 0)
|
||||
local matrix = Matrix()
|
||||
|
||||
matrix:Translate(translation)
|
||||
matrix:Scale(Vector(scale, scale, 0))
|
||||
matrix:Translate(-translation)
|
||||
|
||||
cam.PushModelMatrix(matrix, true)
|
||||
render.PushFilterMin(TEXFILTER.ANISOTROPIC)
|
||||
DisableClipping(true)
|
||||
|
||||
self.bCurrentlyScaling = true
|
||||
end
|
||||
end
|
||||
|
||||
if (self.kerning > 0) then
|
||||
self:DrawKernedText(width, height)
|
||||
else
|
||||
self:DrawText(width, height)
|
||||
end
|
||||
|
||||
if (self.bCurrentlyScaling) then
|
||||
DisableClipping(false)
|
||||
render.PopFilterMin()
|
||||
cam.PopModelMatrix()
|
||||
|
||||
self.bCurrentlyScaling = false
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns the size of the text, taking into account the current kerning.
|
||||
-- @realm client
|
||||
-- @bool[opt=false] bCalculate Whether or not to recalculate the content size instead of using the cached copy
|
||||
-- @treturn number Width of the text
|
||||
-- @treturn number Height of the text
|
||||
function PANEL:GetContentSize(bCalculate)
|
||||
if (bCalculate or !self.contentSize) then
|
||||
surface.SetFont(self.font)
|
||||
|
||||
if (self.kerning > 0) then
|
||||
local width = 0
|
||||
|
||||
for i = 1, self.text:utf8len() do
|
||||
local textWidth, _ = surface.GetTextSize(self.text:utf8sub(i, i))
|
||||
width = width + textWidth + self.kerning
|
||||
end
|
||||
|
||||
self.contentSize = {width, draw.GetFontHeight(self.font)}
|
||||
else
|
||||
self.contentSize = {surface.GetTextSize(self.text)}
|
||||
end
|
||||
end
|
||||
|
||||
return self.contentSize[1], self.contentSize[2]
|
||||
end
|
||||
|
||||
--- Sets the size of the panel to fit the content size with the current padding. The content size is recalculated when this
|
||||
-- method is called.
|
||||
-- @realm client
|
||||
function PANEL:SizeToContents()
|
||||
local contentWidth, contentHeight = self:GetContentSize(true)
|
||||
|
||||
self:SetSize(contentWidth + self.padding * 2, contentHeight + self.padding * 2)
|
||||
end
|
||||
|
||||
vgui.Register("ixLabel", PANEL, "Panel")
|
||||
|
||||
-- text entry with icon
|
||||
DEFINE_BASECLASS("ixTextEntry")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "icon", "Icon", FORCE_STRING)
|
||||
AccessorFunc(PANEL, "iconColor", "IconColor")
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetIcon("V")
|
||||
self:SetFont("ixSmallTitleFont")
|
||||
|
||||
self.iconColor = Color(200, 200, 200, 160)
|
||||
end
|
||||
|
||||
function PANEL:SetIcon(newIcon)
|
||||
surface.SetFont("ixSmallTitleIcons")
|
||||
|
||||
self.iconWidth, self.iconHeight = surface.GetTextSize(newIcon)
|
||||
self.icon = newIcon
|
||||
|
||||
self:DockMargin(self.iconWidth + 4, 0, 0, 8)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
BaseClass.Paint(self, width, height)
|
||||
|
||||
-- there's no inset for text entries so we'll have to get creative
|
||||
DisableClipping(true)
|
||||
surface.SetDrawColor(self:GetBackgroundColor())
|
||||
surface.DrawRect(-self.iconWidth - 4, 0, self.iconWidth + 4, height)
|
||||
|
||||
surface.SetFont("ixSmallTitleIcons")
|
||||
surface.SetTextColor(self.iconColor)
|
||||
surface.SetTextPos(-self.iconWidth - 2, 0)
|
||||
surface.DrawText(self:GetIcon())
|
||||
DisableClipping(false)
|
||||
end
|
||||
|
||||
vgui.Register("ixIconTextEntry", PANEL, "ixTextEntry")
|
||||
379
gamemodes/helix/gamemode/core/derma/cl_help.lua
Normal file
379
gamemodes/helix/gamemode/core/derma/cl_help.lua
Normal file
@@ -0,0 +1,379 @@
|
||||
--[[
|
||||
| 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 backgroundColor = Color(0, 0, 0, 66)
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "maxWidth", "MaxWidth", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetWide(180)
|
||||
self:Dock(LEFT)
|
||||
|
||||
self.maxWidth = ScrW() * 0.2
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
surface.SetDrawColor(backgroundColor)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
local width = 0
|
||||
|
||||
for _, v in ipairs(self:GetChildren()) do
|
||||
width = math.max(width, v:GetWide())
|
||||
end
|
||||
|
||||
self:SetSize(math.max(32, math.min(width, self.maxWidth)), self:GetParent():GetTall())
|
||||
end
|
||||
|
||||
vgui.Register("ixHelpMenuCategories", PANEL, "EditablePanel")
|
||||
|
||||
-- help menu
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:Dock(FILL)
|
||||
|
||||
self.categories = {}
|
||||
self.categorySubpanels = {}
|
||||
self.categoryPanel = self:Add("ixHelpMenuCategories")
|
||||
|
||||
self.canvasPanel = self:Add("EditablePanel")
|
||||
self.canvasPanel:Dock(FILL)
|
||||
|
||||
self.idlePanel = self.canvasPanel:Add("Panel")
|
||||
self.idlePanel:Dock(FILL)
|
||||
self.idlePanel:DockMargin(8, 0, 0, 0)
|
||||
self.idlePanel.Paint = function(_, width, height)
|
||||
surface.SetDrawColor(backgroundColor)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
|
||||
derma.SkinFunc("DrawHelixCurved", width * 0.5, height * 0.5, width * 0.25)
|
||||
|
||||
surface.SetFont("ixIntroSubtitleFont")
|
||||
local text = L("helix"):lower()
|
||||
local textWidth, textHeight = surface.GetTextSize(text)
|
||||
|
||||
surface.SetTextColor(color_white)
|
||||
surface.SetTextPos(width * 0.5 - textWidth * 0.5, height * 0.5 - textHeight * 0.75)
|
||||
surface.DrawText(text)
|
||||
|
||||
surface.SetFont("ixMediumLightFont")
|
||||
text = L("helpIdle")
|
||||
local infoWidth, _ = surface.GetTextSize(text)
|
||||
|
||||
surface.SetTextColor(color_white)
|
||||
surface.SetTextPos(width * 0.5 - infoWidth * 0.5, height * 0.5 + textHeight * 0.25)
|
||||
surface.DrawText(text)
|
||||
end
|
||||
|
||||
local categories = {}
|
||||
hook.Run("PopulateHelpMenu", categories)
|
||||
|
||||
for k, v in SortedPairs(categories) do
|
||||
if (!isstring(k)) then
|
||||
ErrorNoHalt("expected string for help menu key\n")
|
||||
continue
|
||||
elseif (!isfunction(v)) then
|
||||
ErrorNoHalt(string.format("expected function for help menu entry '%s'\n", k))
|
||||
continue
|
||||
end
|
||||
|
||||
self:AddCategory(k)
|
||||
self.categories[k] = v
|
||||
end
|
||||
|
||||
self.categoryPanel:SizeToContents()
|
||||
|
||||
if (ix.gui.lastHelpMenuTab) then
|
||||
self:OnCategorySelected(ix.gui.lastHelpMenuTab)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:AddCategory(name)
|
||||
local button = self.categoryPanel:Add("ixMenuButton")
|
||||
button:SetText(L(name))
|
||||
button:SizeToContents()
|
||||
-- @todo don't hardcode this but it's the only panel that needs docking at the bottom so it'll do for now
|
||||
button:Dock(name == "credits" and BOTTOM or TOP)
|
||||
button.DoClick = function()
|
||||
self:OnCategorySelected(name)
|
||||
end
|
||||
|
||||
local panel = self.canvasPanel:Add("DScrollPanel")
|
||||
panel:SetVisible(false)
|
||||
panel:Dock(FILL)
|
||||
panel:DockMargin(8, 0, 0, 0)
|
||||
panel:GetCanvas():DockPadding(8, 8, 8, 8)
|
||||
|
||||
panel.Paint = function(_, width, height)
|
||||
surface.SetDrawColor(backgroundColor)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
-- reverts functionality back to a standard panel in the case that a category will manage its own scrolling
|
||||
panel.DisableScrolling = function()
|
||||
panel:GetCanvas():SetVisible(false)
|
||||
panel:GetVBar():SetVisible(false)
|
||||
panel.OnChildAdded = function() end
|
||||
end
|
||||
|
||||
self.categorySubpanels[name] = panel
|
||||
end
|
||||
|
||||
function PANEL:OnCategorySelected(name)
|
||||
local panel = self.categorySubpanels[name]
|
||||
|
||||
if (!IsValid(panel)) then
|
||||
return
|
||||
end
|
||||
|
||||
if (!panel.bPopulated) then
|
||||
self.categories[name](panel)
|
||||
panel.bPopulated = true
|
||||
end
|
||||
|
||||
if (IsValid(self.activeCategory)) then
|
||||
self.activeCategory:SetVisible(false)
|
||||
end
|
||||
|
||||
panel:SetVisible(true)
|
||||
self.idlePanel:SetVisible(false)
|
||||
|
||||
self.activeCategory = panel
|
||||
ix.gui.lastHelpMenuTab = name
|
||||
end
|
||||
|
||||
vgui.Register("ixHelpMenu", PANEL, "EditablePanel")
|
||||
|
||||
local function DrawHelix(width, height, color) -- luacheck: ignore 211
|
||||
local segments = 76
|
||||
local radius = math.min(width, height) * 0.375
|
||||
|
||||
surface.SetTexture(-1)
|
||||
|
||||
for i = 1, math.ceil(segments) do
|
||||
local angle = math.rad((i / segments) * -360)
|
||||
local x = width * 0.5 + math.sin(angle + math.pi * 2) * radius
|
||||
local y = height * 0.5 + math.cos(angle + math.pi * 2) * radius
|
||||
local barOffset = math.sin(SysTime() + i * 0.5)
|
||||
local barHeight = barOffset * radius * 0.25
|
||||
|
||||
if (barOffset > 0) then
|
||||
surface.SetDrawColor(color)
|
||||
else
|
||||
surface.SetDrawColor(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
|
||||
end
|
||||
|
||||
surface.DrawTexturedRectRotated(x, y, 4, barHeight, math.deg(angle))
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add("CreateMenuButtons", "ixHelpMenu", function(tabs)
|
||||
tabs["help"] = function(container)
|
||||
container:Add("ixHelpMenu")
|
||||
end
|
||||
end)
|
||||
|
||||
hook.Add("PopulateHelpMenu", "ixHelpMenu", function(tabs)
|
||||
tabs["commands"] = function(container)
|
||||
-- info text
|
||||
local info = container:Add("DLabel")
|
||||
info:SetFont("ixSmallFont")
|
||||
info:SetText(L("helpCommands"))
|
||||
info:SetContentAlignment(5)
|
||||
info:SetTextColor(color_white)
|
||||
info:SetExpensiveShadow(1, color_black)
|
||||
info:Dock(TOP)
|
||||
info:DockMargin(0, 0, 0, 8)
|
||||
info:SizeToContents()
|
||||
info:SetTall(info:GetTall() + 16)
|
||||
|
||||
info.Paint = function(_, width, height)
|
||||
surface.SetDrawColor(ColorAlpha(derma.GetColor("Info", info), 160))
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
-- commands
|
||||
for uniqueID, command in SortedPairs(ix.command.list) do
|
||||
if (command.OnCheckAccess and !command:OnCheckAccess(LocalPlayer())) then
|
||||
continue
|
||||
end
|
||||
|
||||
local bIsAlias = false
|
||||
local aliasText = ""
|
||||
|
||||
-- we want to show aliases in the same entry for better readability
|
||||
if (command.alias) then
|
||||
local alias = istable(command.alias) and command.alias or {command.alias}
|
||||
|
||||
for _, v in ipairs(alias) do
|
||||
if (v:lower() == uniqueID) then
|
||||
bIsAlias = true
|
||||
break
|
||||
end
|
||||
|
||||
aliasText = aliasText .. ", /" .. v
|
||||
end
|
||||
|
||||
if (bIsAlias) then
|
||||
continue
|
||||
end
|
||||
end
|
||||
|
||||
-- command name
|
||||
local title = container:Add("DLabel")
|
||||
title:SetFont("ixMediumLightFont")
|
||||
title:SetText("/" .. command.name .. aliasText)
|
||||
title:Dock(TOP)
|
||||
title:SetTextColor(ix.config.Get("color"))
|
||||
title:SetExpensiveShadow(1, color_black)
|
||||
title:SizeToContents()
|
||||
|
||||
-- syntax
|
||||
local syntaxText = command.syntax
|
||||
local syntax
|
||||
|
||||
if (syntaxText != "" and syntaxText != "[none]") then
|
||||
syntax = container:Add("DLabel")
|
||||
syntax:SetFont("ixMediumLightFont")
|
||||
syntax:SetText(syntaxText)
|
||||
syntax:Dock(TOP)
|
||||
syntax:SetTextColor(color_white)
|
||||
syntax:SetExpensiveShadow(1, color_black)
|
||||
syntax:SetWrap(true)
|
||||
syntax:SetAutoStretchVertical(true)
|
||||
syntax:SizeToContents()
|
||||
end
|
||||
|
||||
-- description
|
||||
local descriptionText = command:GetDescription()
|
||||
|
||||
if (descriptionText != "") then
|
||||
local description = container:Add("DLabel")
|
||||
description:SetFont("ixSmallFont")
|
||||
description:SetText(descriptionText)
|
||||
description:Dock(TOP)
|
||||
description:SetTextColor(color_white)
|
||||
description:SetExpensiveShadow(1, color_black)
|
||||
description:SetWrap(true)
|
||||
description:SetAutoStretchVertical(true)
|
||||
description:SizeToContents()
|
||||
description:DockMargin(0, 0, 0, 8)
|
||||
elseif (syntax) then
|
||||
syntax:DockMargin(0, 0, 0, 8)
|
||||
else
|
||||
title:DockMargin(0, 0, 0, 8)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tabs["flags"] = function(container)
|
||||
-- info text
|
||||
local info = container:Add("DLabel")
|
||||
info:SetFont("ixSmallFont")
|
||||
info:SetText(L("helpFlags"))
|
||||
info:SetContentAlignment(5)
|
||||
info:SetTextColor(color_white)
|
||||
info:SetExpensiveShadow(1, color_black)
|
||||
info:Dock(TOP)
|
||||
info:DockMargin(0, 0, 0, 8)
|
||||
info:SizeToContents()
|
||||
info:SetTall(info:GetTall() + 16)
|
||||
|
||||
info.Paint = function(_, width, height)
|
||||
surface.SetDrawColor(ColorAlpha(derma.GetColor("Info", info), 160))
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
-- flags
|
||||
for k, v in SortedPairs(ix.flag.list) do
|
||||
local background = ColorAlpha(
|
||||
LocalPlayer():GetCharacter():HasFlags(k) and derma.GetColor("Success", info) or derma.GetColor("Error", info), 88
|
||||
)
|
||||
|
||||
local panel = container:Add("Panel")
|
||||
panel:Dock(TOP)
|
||||
panel:DockMargin(0, 0, 0, 8)
|
||||
panel:DockPadding(4, 4, 4, 4)
|
||||
panel.Paint = function(_, width, height)
|
||||
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, background)
|
||||
end
|
||||
|
||||
local flag = panel:Add("DLabel")
|
||||
flag:SetFont("ixMonoMediumFont")
|
||||
flag:SetText(string.format("[%s]", k))
|
||||
flag:Dock(LEFT)
|
||||
flag:SetTextColor(color_white)
|
||||
flag:SetExpensiveShadow(1, color_black)
|
||||
flag:SetTextInset(4, 0)
|
||||
flag:SizeToContents()
|
||||
flag:SetTall(flag:GetTall() + 8)
|
||||
|
||||
local description = panel:Add("DLabel")
|
||||
description:SetFont("ixMediumLightFont")
|
||||
description:SetText(v.description)
|
||||
description:Dock(FILL)
|
||||
description:SetTextColor(color_white)
|
||||
description:SetExpensiveShadow(1, color_black)
|
||||
description:SetTextInset(8, 0)
|
||||
description:SizeToContents()
|
||||
description:SetTall(description:GetTall() + 8)
|
||||
|
||||
panel:SizeToChildren(false, true)
|
||||
end
|
||||
end
|
||||
|
||||
tabs["plugins"] = function(container)
|
||||
for _, v in SortedPairsByMemberValue(ix.plugin.list, "name") do
|
||||
-- name
|
||||
local title = container:Add("DLabel")
|
||||
title:SetFont("ixMediumLightFont")
|
||||
title:SetText(v.name or "Unknown")
|
||||
title:Dock(TOP)
|
||||
title:SetTextColor(ix.config.Get("color"))
|
||||
title:SetExpensiveShadow(1, color_black)
|
||||
title:SizeToContents()
|
||||
|
||||
-- author
|
||||
local author = container:Add("DLabel")
|
||||
author:SetFont("ixSmallFont")
|
||||
author:SetText(string.format("%s: %s", L("author"), v.author))
|
||||
author:Dock(TOP)
|
||||
author:SetTextColor(color_white)
|
||||
author:SetExpensiveShadow(1, color_black)
|
||||
author:SetWrap(true)
|
||||
author:SetAutoStretchVertical(true)
|
||||
author:SizeToContents()
|
||||
|
||||
-- description
|
||||
local descriptionText = v.description
|
||||
|
||||
if (descriptionText != "") then
|
||||
local description = container:Add("DLabel")
|
||||
description:SetFont("ixSmallFont")
|
||||
description:SetText(descriptionText)
|
||||
description:Dock(TOP)
|
||||
description:SetTextColor(color_white)
|
||||
description:SetExpensiveShadow(1, color_black)
|
||||
description:SetWrap(true)
|
||||
description:SetAutoStretchVertical(true)
|
||||
description:SizeToContents()
|
||||
description:DockMargin(0, 0, 0, 8)
|
||||
else
|
||||
author:DockMargin(0, 0, 0, 8)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
283
gamemodes/helix/gamemode/core/derma/cl_information.lua
Normal file
283
gamemodes/helix/gamemode/core/derma/cl_information.lua
Normal file
@@ -0,0 +1,283 @@
|
||||
--[[
|
||||
| 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 = {}
|
||||
|
||||
function PANEL:Init()
|
||||
local parent = self:GetParent()
|
||||
|
||||
self:SetSize(parent:GetWide() * 0.6, parent:GetTall())
|
||||
self:Dock(RIGHT)
|
||||
self:DockMargin(0, ScrH() * 0.05, 0, 0)
|
||||
|
||||
self.VBar:SetWide(0)
|
||||
|
||||
-- entry setup
|
||||
local suppress = {}
|
||||
hook.Run("CanCreateCharacterInfo", suppress)
|
||||
|
||||
if (!suppress.time) then
|
||||
local format = "%A, %B %d, %Y. %H:%M"
|
||||
|
||||
self.time = self:Add("DLabel")
|
||||
self.time:SetFont("ixMediumFont")
|
||||
self.time:SetTall(28)
|
||||
self.time:SetContentAlignment(5)
|
||||
self.time:Dock(TOP)
|
||||
self.time:SetTextColor(color_white)
|
||||
self.time:SetExpensiveShadow(1, Color(0, 0, 0, 150))
|
||||
self.time:DockMargin(0, 0, 0, 32)
|
||||
self.time:SetText(ix.date.GetFormatted(format))
|
||||
self.time.Think = function(this)
|
||||
if ((this.nextTime or 0) < CurTime()) then
|
||||
this:SetText(ix.date.GetFormatted(format))
|
||||
this.nextTime = CurTime() + 0.5
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (!suppress.name) then
|
||||
self.name = self:Add("ixLabel")
|
||||
self.name:Dock(TOP)
|
||||
self.name:DockMargin(0, 0, 0, 8)
|
||||
self.name:SetFont("ixMenuButtonHugeFont")
|
||||
self.name:SetContentAlignment(5)
|
||||
self.name:SetTextColor(color_white)
|
||||
self.name:SetPadding(8)
|
||||
self.name:SetScaleWidth(true)
|
||||
end
|
||||
|
||||
if (!suppress.description) then
|
||||
self.description = self:Add("DLabel")
|
||||
self.description:Dock(TOP)
|
||||
self.description:DockMargin(0, 0, 0, 8)
|
||||
self.description:SetFont("ixMenuButtonFont")
|
||||
self.description:SetTextColor(color_white)
|
||||
self.description:SetContentAlignment(5)
|
||||
self.description:SetMouseInputEnabled(true)
|
||||
self.description:SetCursor("hand")
|
||||
|
||||
self.description.Paint = function(this, width, height)
|
||||
surface.SetDrawColor(0, 0, 0, 150)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
self.description.OnMousePressed = function(this, code)
|
||||
if (code == MOUSE_LEFT) then
|
||||
ix.command.Send("CharDesc")
|
||||
|
||||
if (IsValid(ix.gui.menu)) then
|
||||
ix.gui.menu:Remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.description.SizeToContents = function(this)
|
||||
if (this.bWrap) then
|
||||
-- sizing contents after initial wrapping does weird things so we'll just ignore (lol)
|
||||
return
|
||||
end
|
||||
|
||||
local width, height = this:GetContentSize()
|
||||
|
||||
if (width > self:GetWide()) then
|
||||
this:SetWide(self:GetWide())
|
||||
this:SetTextInset(16, 8)
|
||||
this:SetWrap(true)
|
||||
this:SizeToContentsY()
|
||||
this:SetTall(this:GetTall() + 16) -- eh
|
||||
|
||||
-- wrapping doesn't like middle alignment so we'll do top-center
|
||||
self.description:SetContentAlignment(8)
|
||||
this.bWrap = true
|
||||
else
|
||||
this:SetSize(width + 16, height + 16)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (!suppress.characterInfo) then
|
||||
self.characterInfo = self:Add("Panel")
|
||||
self.characterInfo.list = {}
|
||||
self.characterInfo:Dock(TOP) -- no dock margin because this is handled by ixListRow
|
||||
self.characterInfo.SizeToContents = function(this)
|
||||
local height = 0
|
||||
|
||||
for _, v in ipairs(this:GetChildren()) do
|
||||
if (IsValid(v) and v:IsVisible()) then
|
||||
local _, top, _, bottom = v:GetDockMargin()
|
||||
height = height + v:GetTall() + top + bottom
|
||||
end
|
||||
end
|
||||
|
||||
this:SetTall(height)
|
||||
end
|
||||
|
||||
if (!suppress.faction) then
|
||||
self.faction = self.characterInfo:Add("ixListRow")
|
||||
self.faction:SetList(self.characterInfo.list)
|
||||
self.faction:Dock(TOP)
|
||||
end
|
||||
|
||||
if (!suppress.class) then
|
||||
self.class = self.characterInfo:Add("ixListRow")
|
||||
self.class:SetList(self.characterInfo.list)
|
||||
self.class:Dock(TOP)
|
||||
end
|
||||
|
||||
if (!suppress.money) then
|
||||
self.money = self.characterInfo:Add("ixListRow")
|
||||
self.money:SetList(self.characterInfo.list)
|
||||
self.money:Dock(TOP)
|
||||
self.money:SizeToContents()
|
||||
end
|
||||
|
||||
hook.Run("CreateCharacterInfo", self.characterInfo)
|
||||
self.characterInfo:SizeToContents()
|
||||
end
|
||||
|
||||
-- no need to update since we aren't showing the attributes panel
|
||||
if (!suppress.attributes) then
|
||||
local character = LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()
|
||||
|
||||
if (character) then
|
||||
self.attributes = self:Add("ixCategoryPanel")
|
||||
self.attributes:SetText(L("attributes"))
|
||||
self.attributes:Dock(TOP)
|
||||
self.attributes:DockMargin(0, 0, 0, 8)
|
||||
|
||||
local boost = character:GetBoosts()
|
||||
local bFirst = true
|
||||
|
||||
for k, v in SortedPairsByMemberValue(ix.attributes.list, "name") do
|
||||
local attributeBoost = 0
|
||||
|
||||
if (boost[k]) then
|
||||
for _, bValue in pairs(boost[k]) do
|
||||
attributeBoost = attributeBoost + bValue
|
||||
end
|
||||
end
|
||||
|
||||
local bar = self.attributes:Add("ixAttributeBar")
|
||||
bar:Dock(TOP)
|
||||
|
||||
if (!bFirst) then
|
||||
bar:DockMargin(0, 3, 0, 0)
|
||||
else
|
||||
bFirst = false
|
||||
end
|
||||
|
||||
local value = character:GetAttribute(k, 0)
|
||||
|
||||
if (attributeBoost) then
|
||||
bar:SetValue(value - attributeBoost or 0)
|
||||
else
|
||||
bar:SetValue(value)
|
||||
end
|
||||
|
||||
local maximum = v.maxValue or ix.config.Get("maxAttributes", 100)
|
||||
bar:SetMax(maximum)
|
||||
bar:SetReadOnly()
|
||||
bar:SetText(Format("%s [%.1f/%.1f] (%.1f%%)", L(v.name), value, maximum, value / maximum * 100))
|
||||
|
||||
if (attributeBoost) then
|
||||
bar:SetBoost(attributeBoost)
|
||||
end
|
||||
end
|
||||
|
||||
self.attributes:SizeToContents()
|
||||
end
|
||||
end
|
||||
|
||||
hook.Run("CreateCharacterInfoCategory", self)
|
||||
end
|
||||
|
||||
function PANEL:Update(character)
|
||||
if (!character) then
|
||||
return
|
||||
end
|
||||
|
||||
local faction = ix.faction.indices[character:GetFaction()]
|
||||
local class = ix.class.list[character:GetClass()]
|
||||
|
||||
if (self.name) then
|
||||
self.name:SetText(character:GetName())
|
||||
|
||||
if (faction) then
|
||||
self.name.backgroundColor = ColorAlpha(faction.color, 150) or Color(0, 0, 0, 150)
|
||||
end
|
||||
|
||||
self.name:SizeToContents()
|
||||
end
|
||||
|
||||
if (self.description) then
|
||||
self.description:SetText(character:GetDescription())
|
||||
self.description:SizeToContents()
|
||||
end
|
||||
|
||||
if (self.faction) then
|
||||
self.faction:SetLabelText(L("faction"))
|
||||
self.faction:SetText(L(faction.name))
|
||||
self.faction:SizeToContents()
|
||||
end
|
||||
|
||||
if (self.class) then
|
||||
-- don't show class label if the class is the same name as the faction
|
||||
if (class and class.name != faction.name) then
|
||||
self.class:SetLabelText(L("class"))
|
||||
self.class:SetText(L(class.name))
|
||||
self.class:SizeToContents()
|
||||
else
|
||||
self.class:SetVisible(false)
|
||||
end
|
||||
end
|
||||
|
||||
if (self.money) then
|
||||
self.money:SetLabelText(L("money"))
|
||||
self.money:SetText(ix.currency.Get(character:GetMoney()))
|
||||
self.money:SizeToContents()
|
||||
end
|
||||
|
||||
hook.Run("UpdateCharacterInfo", self.characterInfo, character)
|
||||
|
||||
self.characterInfo:SizeToContents()
|
||||
|
||||
hook.Run("UpdateCharacterInfoCategory", self, character)
|
||||
end
|
||||
|
||||
function PANEL:OnSubpanelRightClick()
|
||||
properties.OpenEntityMenu(LocalPlayer())
|
||||
end
|
||||
|
||||
vgui.Register("ixCharacterInfo", PANEL, "DScrollPanel")
|
||||
|
||||
hook.Add("CreateMenuButtons", "ixCharInfo", function(tabs)
|
||||
tabs["you"] = {
|
||||
bHideBackground = true,
|
||||
buttonColor = team.GetColor(LocalPlayer():Team()),
|
||||
Create = function(info, container)
|
||||
container.infoPanel = container:Add("ixCharacterInfo")
|
||||
|
||||
container.OnMouseReleased = function(this, key)
|
||||
if (key == MOUSE_RIGHT) then
|
||||
this.infoPanel:OnSubpanelRightClick()
|
||||
end
|
||||
end
|
||||
end,
|
||||
OnSelected = function(info, container)
|
||||
container.infoPanel:Update(LocalPlayer():GetCharacter())
|
||||
ix.gui.menu:SetCharacterOverview(true)
|
||||
end,
|
||||
OnDeselected = function(info, container)
|
||||
ix.gui.menu:SetCharacterOverview(false)
|
||||
end
|
||||
}
|
||||
end)
|
||||
378
gamemodes/helix/gamemode/core/derma/cl_intro.lua
Normal file
378
gamemodes/helix/gamemode/core/derma/cl_intro.lua
Normal file
@@ -0,0 +1,378 @@
|
||||
--[[
|
||||
| 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 waveSegments = 32
|
||||
local helixSegments = 76
|
||||
local helixHeight = 64
|
||||
local backgroundColor = Color(115, 53, 142)
|
||||
local dimColor = Color(165, 134, 179)
|
||||
|
||||
DEFINE_BASECLASS("EditablePanel")
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
if (IsValid(ix.gui.intro)) then
|
||||
ix.gui.intro:Remove()
|
||||
end
|
||||
|
||||
ix.gui.intro = self
|
||||
|
||||
self:SetSize(ScrW(), ScrH())
|
||||
self:SetPos(0, 0)
|
||||
self:SetZPos(99999)
|
||||
self:MakePopup()
|
||||
|
||||
-- animation parameters
|
||||
self.bBackground = true
|
||||
self.volume = 1
|
||||
self.sunbeamOffset = 0
|
||||
self.textOne = 0
|
||||
self.textTwo = 0
|
||||
self.kickTarget = 0
|
||||
self.helix = 0
|
||||
self.helixAlpha = 0
|
||||
self.continueText = 0
|
||||
self.pulse = 0
|
||||
|
||||
self.waves = {
|
||||
{1.1, 0},
|
||||
{1.1, math.pi},
|
||||
{1.1, math.pi * 1.6},
|
||||
{1.1, math.pi * 0.5}
|
||||
}
|
||||
end
|
||||
|
||||
-- @todo h a c k
|
||||
function PANEL:Think()
|
||||
if (IsValid(LocalPlayer())) then
|
||||
self:BeginIntro()
|
||||
self.Think = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:BeginIntro()
|
||||
-- something could have errored on startup and invalidated all options, so we'll be extra careful with setting the option
|
||||
-- because if it errors here, the sound will play each tick and proceed to hurt ears
|
||||
local bLoaded = false
|
||||
|
||||
if (ix and ix.option and ix.option.Set) then
|
||||
local bSuccess, _ = pcall(ix.option.Set, "showIntro", false)
|
||||
bLoaded = bSuccess
|
||||
end
|
||||
|
||||
if (!bLoaded) then
|
||||
self:Remove()
|
||||
|
||||
if (ix and ix.gui and IsValid(ix.gui.characterMenu)) then
|
||||
ix.gui.characterMenu:Remove()
|
||||
end
|
||||
|
||||
ErrorNoHalt(
|
||||
"[Helix] Something has errored and prevented the framework from loading correctly - check your console for errors!\n")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:MoveToFront()
|
||||
self:RequestFocus()
|
||||
|
||||
sound.PlayFile("sound/buttons/combine_button2.wav", "", function()
|
||||
timer.Create("ixIntroStart", 2, 1, function()
|
||||
sound.PlayFile("sound/helix/intro.mp3", "", function(channel, status, error)
|
||||
if (IsValid(channel)) then
|
||||
channel:SetVolume(self.volume)
|
||||
self.channel = channel
|
||||
end
|
||||
|
||||
self:BeginAnimation()
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
function PANEL:AnimateWaves(target, bReverse)
|
||||
for i = bReverse and #self.waves or 1,
|
||||
bReverse and 1 or #self.waves,
|
||||
bReverse and -1 or 1 do
|
||||
|
||||
local animation = self:CreateAnimation(2, {
|
||||
index = 20 + (bReverse and (#self.waves - i) or i),
|
||||
bAutoFire = false,
|
||||
target = {
|
||||
waves = {
|
||||
[i] = {target}
|
||||
}
|
||||
},
|
||||
easing = bReverse and "inQuart" or "outQuint"
|
||||
})
|
||||
|
||||
timer.Simple((bReverse and (#self.waves - i) or i) * 0.1, function()
|
||||
if (IsValid(self) and animation) then
|
||||
animation:Fire()
|
||||
end
|
||||
end)
|
||||
|
||||
-- return last animation that plays
|
||||
if ((bReverse and i == 1) or (!bReverse and i == #self.waves)) then
|
||||
return animation
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:BeginAnimation()
|
||||
self:CreateAnimation(2, {
|
||||
target = {textOne = 1},
|
||||
easing = "inQuint",
|
||||
bIgnoreConfig = true
|
||||
})
|
||||
:CreateAnimation(2, {
|
||||
target = {textOne = 0},
|
||||
easing = "inQuint",
|
||||
bIgnoreConfig = true
|
||||
})
|
||||
:CreateAnimation(2, {
|
||||
target = {textTwo = 1},
|
||||
easing = "inQuint",
|
||||
bIgnoreConfig = true,
|
||||
OnComplete = function(animation, panel)
|
||||
self:AnimateWaves(0)
|
||||
end
|
||||
})
|
||||
:CreateAnimation(2, {
|
||||
target = {textTwo = 0},
|
||||
easing = "inQuint",
|
||||
bIgnoreConfig = true
|
||||
})
|
||||
:CreateAnimation(4, {
|
||||
target = {sunbeamOffset = 1},
|
||||
bIgnoreConfig = true,
|
||||
OnComplete = function()
|
||||
self:CreateAnimation(2,{
|
||||
target = {helixAlpha = 1},
|
||||
easing = "inCubic"
|
||||
})
|
||||
end
|
||||
})
|
||||
:CreateAnimation(2, {
|
||||
target = {helix = 1},
|
||||
easing = "outQuart",
|
||||
bIgnoreConfig = true
|
||||
})
|
||||
:CreateAnimation(2, {
|
||||
target = {continueText = 1},
|
||||
easing = "linear",
|
||||
bIgnoreConfig = true
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:PaintCurve(y, width, offset, scale)
|
||||
offset = offset or 1
|
||||
scale = scale or 32
|
||||
|
||||
local points = {
|
||||
[1] = {
|
||||
x = 0,
|
||||
y = ScrH()
|
||||
}
|
||||
}
|
||||
|
||||
for i = 0, waveSegments do
|
||||
local angle = math.rad((i / waveSegments) * -360)
|
||||
|
||||
points[#points + 1] = {
|
||||
x = (width / waveSegments) * i,
|
||||
y = y + (math.sin(angle * 0.5 + offset) - 1) * scale
|
||||
}
|
||||
end
|
||||
|
||||
points[#points + 1] = {
|
||||
x = width,
|
||||
y = ScrH()
|
||||
}
|
||||
|
||||
draw.NoTexture()
|
||||
surface.DrawPoly(points)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
local time = SysTime()
|
||||
local text = L("helix"):lower()
|
||||
local centerY = height * self.waves[#self.waves][1] + height * 0.5
|
||||
local sunbeamOffsetEasing = math.sin(math.pi * self.sunbeamOffset)
|
||||
local textWidth, textHeight
|
||||
local fft
|
||||
|
||||
-- background
|
||||
if (self.bBackground) then
|
||||
surface.SetDrawColor(0, 0, 0, 255)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
if (self.sunbeamOffset == 1) then
|
||||
fft = {}
|
||||
|
||||
if (IsValid(self.channel)) then
|
||||
self.channel:FFT(fft, FFT_2048)
|
||||
|
||||
local kick = (fft[4] or 0) * 8192
|
||||
self.kickTarget = math.Approach(self.kickTarget, kick, 8 * math.abs(kick - self.kickTarget) * FrameTime())
|
||||
end
|
||||
end
|
||||
|
||||
-- waves
|
||||
for i = 1, #self.waves do
|
||||
local wave = self.waves[i]
|
||||
local ratio = i / #self.waves
|
||||
local color = Color(
|
||||
backgroundColor.r * ratio,
|
||||
backgroundColor.g * ratio,
|
||||
backgroundColor.b * ratio,
|
||||
self.bBackground and 255 or (ratio * 320)
|
||||
)
|
||||
|
||||
surface.SetDrawColor(color)
|
||||
self:PaintCurve(height * wave[1], width, wave[2])
|
||||
end
|
||||
|
||||
-- helix
|
||||
if (self.helix > 0) then
|
||||
local alpha = self.helixAlpha * 255
|
||||
|
||||
derma.SkinFunc("DrawHelixCurved",
|
||||
width * 0.5, centerY,
|
||||
math.min(ScreenScale(72), 128) * 2, -- font sizes are clamped to 128
|
||||
helixSegments * self.helix, helixHeight, self.helix,
|
||||
ColorAlpha(color_white, alpha),
|
||||
ColorAlpha(dimColor, alpha)
|
||||
)
|
||||
end
|
||||
|
||||
-- title text glow
|
||||
surface.SetTextColor(255, 255, 255,
|
||||
self.sunbeamOffset == 1 and self.kickTarget or sunbeamOffsetEasing * 255
|
||||
)
|
||||
surface.SetFont("ixIntroTitleBlurFont")
|
||||
|
||||
local logoTextWidth, logoTextHeight = surface.GetTextSize(text)
|
||||
surface.SetTextPos(width * 0.5 - logoTextWidth * 0.5, centerY - logoTextHeight * 0.5)
|
||||
surface.DrawText(text)
|
||||
|
||||
-- title text
|
||||
surface.SetTextColor(255, 255, 255, self.sunbeamOffset * 255)
|
||||
surface.SetFont("ixIntroTitleFont")
|
||||
|
||||
logoTextWidth, logoTextHeight = surface.GetTextSize(text)
|
||||
surface.SetTextPos(width * 0.5 - logoTextWidth * 0.5, centerY - logoTextHeight * 0.5)
|
||||
surface.DrawText(text)
|
||||
|
||||
-- text one
|
||||
surface.SetFont("ixIntroSubtitleFont")
|
||||
text = L("introTextOne"):lower()
|
||||
textWidth = surface.GetTextSize(text)
|
||||
|
||||
surface.SetTextColor(255, 255, 255, self.textOne * 255)
|
||||
surface.SetTextPos(width * 0.5 - textWidth * 0.5, height * 0.66)
|
||||
surface.DrawText(text)
|
||||
|
||||
-- text two
|
||||
text = L("introTextTwo", Schema.author or "nebulous"):lower()
|
||||
textWidth = surface.GetTextSize(text)
|
||||
|
||||
surface.SetTextColor(255, 255, 255, self.textTwo * 255)
|
||||
surface.SetTextPos(width * 0.5 - textWidth * 0.5, height * 0.66)
|
||||
surface.DrawText(text)
|
||||
|
||||
-- continue text
|
||||
surface.SetFont("ixIntroSmallFont")
|
||||
text = L("introContinue"):lower()
|
||||
textWidth, textHeight = surface.GetTextSize(text)
|
||||
|
||||
if (self.continueText == 1) then
|
||||
self.pulse = self.pulse + 6 * FrameTime()
|
||||
|
||||
if (self.pulse >= 360) then
|
||||
self.pulse = 0
|
||||
end
|
||||
end
|
||||
|
||||
surface.SetTextColor(255, 255, 255, self.continueText * 255 - (math.sin(self.pulse) * 100), 0)
|
||||
surface.SetTextPos(width * 0.5 - textWidth * 0.5, centerY * 2 - textHeight * 2)
|
||||
surface.DrawText(text)
|
||||
|
||||
-- sunbeams
|
||||
if (self.sunbeamOffset > 0 and self.sunbeamOffset != 1) then
|
||||
DrawSunbeams(0.25, sunbeamOffsetEasing * 0.1, 0.02,
|
||||
(((width * 0.5 - logoTextWidth * 0.5) - 32) / width) + ((logoTextWidth + 64) / width) * self.sunbeamOffset,
|
||||
0.5 + math.sin(time * 2) * 0.01
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnKeyCodePressed(key)
|
||||
if (key == KEY_SPACE and self.continueText > 0.25) then
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnRemove()
|
||||
timer.Remove("ixIntroStart")
|
||||
|
||||
if (IsValid(self.channel)) then
|
||||
self.channel:Stop()
|
||||
end
|
||||
|
||||
if (IsValid(ix.gui.characterMenu)) then
|
||||
ix.gui.characterMenu:PlayMusic()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Remove(bForce)
|
||||
if (bForce) then
|
||||
BaseClass.Remove(self)
|
||||
return
|
||||
end
|
||||
|
||||
if (self.bClosing) then
|
||||
return
|
||||
end
|
||||
|
||||
self.bClosing = true
|
||||
self.bBackground = nil
|
||||
|
||||
-- waves
|
||||
local animation = self:AnimateWaves(1.1, true)
|
||||
|
||||
animation.OnComplete = function(anim, panel)
|
||||
panel:SetMouseInputEnabled(false)
|
||||
panel:SetKeyboardInputEnabled(false)
|
||||
end
|
||||
|
||||
-- audio
|
||||
self:CreateAnimation(4.5, {
|
||||
index = 1,
|
||||
target = {volume = 0},
|
||||
|
||||
Think = function(anim, panel)
|
||||
if (IsValid(panel.channel)) then
|
||||
panel.channel:SetVolume(panel.volume)
|
||||
end
|
||||
end,
|
||||
|
||||
OnComplete = function()
|
||||
timer.Simple(0, function()
|
||||
BaseClass.Remove(self)
|
||||
end)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
vgui.Register("ixIntro", PANEL, "EditablePanel")
|
||||
806
gamemodes/helix/gamemode/core/derma/cl_inventory.lua
Normal file
806
gamemodes/helix/gamemode/core/derma/cl_inventory.lua
Normal file
@@ -0,0 +1,806 @@
|
||||
--[[
|
||||
| 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 RECEIVER_NAME = "ixInventoryItem"
|
||||
|
||||
-- The queue for the rendered icons.
|
||||
ICON_RENDER_QUEUE = ICON_RENDER_QUEUE or {}
|
||||
|
||||
-- To make making inventory variant, This must be followed up.
|
||||
local function RenderNewIcon(panel, itemTable)
|
||||
local model = itemTable:GetModel()
|
||||
|
||||
-- re-render icons
|
||||
if ((itemTable.iconCam and !ICON_RENDER_QUEUE[string.lower(model)]) or itemTable.forceRender) then
|
||||
local iconCam = itemTable.iconCam
|
||||
iconCam = {
|
||||
cam_pos = iconCam.pos,
|
||||
cam_ang = iconCam.ang,
|
||||
cam_fov = iconCam.fov,
|
||||
}
|
||||
ICON_RENDER_QUEUE[string.lower(model)] = true
|
||||
|
||||
panel.Icon:RebuildSpawnIconEx(
|
||||
iconCam
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
local function InventoryAction(action, itemID, invID, data)
|
||||
net.Start("ixInventoryAction")
|
||||
net.WriteString(action)
|
||||
net.WriteUInt(itemID, 32)
|
||||
net.WriteUInt(invID, 32)
|
||||
net.WriteTable(data or {})
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "itemTable", "ItemTable")
|
||||
AccessorFunc(PANEL, "inventoryID", "InventoryID")
|
||||
|
||||
function PANEL:Init()
|
||||
self:Droppable(RECEIVER_NAME)
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed(code)
|
||||
if (code == MOUSE_LEFT and self:IsDraggable()) then
|
||||
self:MouseCapture(true)
|
||||
self:DragMousePress(code)
|
||||
|
||||
self.clickX, self.clickY = input.GetCursorPos()
|
||||
elseif (code == MOUSE_RIGHT and self.DoRightClick) then
|
||||
self:DoRightClick()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnMouseReleased(code)
|
||||
-- move the item into the world if we're dropping on something that doesn't handle inventory item drops
|
||||
if (!dragndrop.m_ReceiverSlot or dragndrop.m_ReceiverSlot.Name != RECEIVER_NAME) then
|
||||
self:OnDrop(dragndrop.IsDragging())
|
||||
end
|
||||
|
||||
self:DragMouseRelease(code)
|
||||
self:SetZPos(99)
|
||||
self:MouseCapture(false)
|
||||
end
|
||||
|
||||
function PANEL:DoRightClick()
|
||||
local itemTable = self.itemTable
|
||||
local inventory = self.inventoryID
|
||||
|
||||
if (itemTable and inventory) then
|
||||
itemTable.player = LocalPlayer()
|
||||
|
||||
local menu = DermaMenu()
|
||||
local override = hook.Run("CreateItemInteractionMenu", self, menu, itemTable)
|
||||
|
||||
if (override == true) then
|
||||
if (menu.Remove) then
|
||||
menu:Remove()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
for k, v in SortedPairs(itemTable.functions) do
|
||||
if (k == "drop" or k == "combine" or (v.OnCanRun and v.OnCanRun(itemTable) == false)) then
|
||||
continue
|
||||
end
|
||||
|
||||
-- is Multi-Option Function
|
||||
if (v.isMulti) then
|
||||
local subMenu, subMenuOption = menu:AddSubMenu(L(v.name or k), function()
|
||||
itemTable.player = LocalPlayer()
|
||||
local send = true
|
||||
|
||||
if (v.OnClick) then
|
||||
send = v.OnClick(itemTable)
|
||||
end
|
||||
|
||||
if (v.sound) then
|
||||
surface.PlaySound(v.sound)
|
||||
end
|
||||
|
||||
if (send != false) then
|
||||
InventoryAction(k, itemTable.id, inventory)
|
||||
end
|
||||
itemTable.player = nil
|
||||
end)
|
||||
subMenuOption:SetImage(v.icon or "icon16/brick.png")
|
||||
|
||||
if (v.multiOptions) then
|
||||
local options = isfunction(v.multiOptions) and v.multiOptions(itemTable, LocalPlayer()) or v.multiOptions
|
||||
|
||||
for _, sub in pairs(options) do
|
||||
subMenu:AddOption(L(sub.name or "subOption"), function()
|
||||
itemTable.player = LocalPlayer()
|
||||
local send = true
|
||||
|
||||
if (sub.OnClick) then
|
||||
send = sub.OnClick(itemTable)
|
||||
end
|
||||
|
||||
if (sub.sound) then
|
||||
surface.PlaySound(sub.sound)
|
||||
end
|
||||
|
||||
if (send != false) then
|
||||
InventoryAction(k, itemTable.id, inventory, sub.data)
|
||||
end
|
||||
itemTable.player = nil
|
||||
end)
|
||||
end
|
||||
end
|
||||
else
|
||||
menu:AddOption(L(v.name or k), function()
|
||||
itemTable.player = LocalPlayer()
|
||||
local send = true
|
||||
|
||||
if (v.OnClick) then
|
||||
send = v.OnClick(itemTable)
|
||||
end
|
||||
|
||||
if (v.sound) then
|
||||
surface.PlaySound(v.sound)
|
||||
end
|
||||
|
||||
if (send != false) then
|
||||
InventoryAction(k, itemTable.id, inventory)
|
||||
end
|
||||
itemTable.player = nil
|
||||
end):SetImage(v.icon or "icon16/brick.png")
|
||||
end
|
||||
end
|
||||
|
||||
-- we want drop to show up as the last option
|
||||
local info = itemTable.functions.drop
|
||||
|
||||
if (info and info.OnCanRun and info.OnCanRun(itemTable) != false) then
|
||||
menu:AddOption(L(info.name or "drop"), function()
|
||||
itemTable.player = LocalPlayer()
|
||||
local send = true
|
||||
|
||||
if (info.OnClick) then
|
||||
send = info.OnClick(itemTable)
|
||||
end
|
||||
|
||||
if (info.sound) then
|
||||
surface.PlaySound(info.sound)
|
||||
end
|
||||
|
||||
if (send != false) then
|
||||
InventoryAction("drop", itemTable.id, inventory)
|
||||
end
|
||||
itemTable.player = nil
|
||||
end):SetImage(info.icon or "icon16/brick.png")
|
||||
end
|
||||
|
||||
menu:Open()
|
||||
itemTable.player = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnDrop(bDragging, inventoryPanel, inventory, gridX, gridY)
|
||||
local item = self.itemTable
|
||||
|
||||
if (!item or !bDragging) then
|
||||
return
|
||||
end
|
||||
|
||||
if (!IsValid(inventoryPanel)) then
|
||||
local inventoryID = self.inventoryID
|
||||
|
||||
if (inventoryID) then
|
||||
InventoryAction("drop", item.id, inventoryID, {})
|
||||
end
|
||||
elseif (inventoryPanel:IsAllEmpty(gridX, gridY, item.width, item.height, self)) then
|
||||
local oldX, oldY = self.gridX, self.gridY
|
||||
|
||||
if (oldX != gridX or oldY != gridY or self.inventoryID != inventoryPanel.invID) then
|
||||
self:Move(gridX, gridY, inventoryPanel)
|
||||
end
|
||||
elseif (inventoryPanel.combineItem) then
|
||||
local combineItem = inventoryPanel.combineItem
|
||||
local inventoryID = combineItem.invID
|
||||
|
||||
if (inventoryID) then
|
||||
combineItem.player = LocalPlayer()
|
||||
if (combineItem.functions.combine.sound) then
|
||||
surface.PlaySound(combineItem.functions.combine.sound)
|
||||
end
|
||||
|
||||
InventoryAction("combine", combineItem.id, inventoryID, {item.id})
|
||||
combineItem.player = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Move(newX, newY, givenInventory, bNoSend)
|
||||
local iconSize = givenInventory.iconSize
|
||||
local oldX, oldY = self.gridX, self.gridY
|
||||
local oldParent = self:GetParent()
|
||||
|
||||
if (givenInventory:OnTransfer(oldX, oldY, newX, newY, oldParent, bNoSend) == false) then
|
||||
return
|
||||
end
|
||||
|
||||
local x = (newX - 1) * iconSize + 4
|
||||
local y = (newY - 1) * iconSize + givenInventory:GetPadding(2)
|
||||
|
||||
self.gridX = newX
|
||||
self.gridY = newY
|
||||
|
||||
self:SetParent(givenInventory)
|
||||
self:SetPos(x, y)
|
||||
|
||||
if (self.slots) then
|
||||
for _, v in ipairs(self.slots) do
|
||||
if (IsValid(v) and v.item == self) then
|
||||
v.item = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.slots = {}
|
||||
|
||||
for currentX = 1, self.gridW do
|
||||
for currentY = 1, self.gridH do
|
||||
local slot = givenInventory.slots[self.gridX + currentX - 1][self.gridY + currentY - 1]
|
||||
|
||||
slot.item = self
|
||||
self.slots[#self.slots + 1] = slot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:PaintOver(width, height)
|
||||
local itemTable = self.itemTable
|
||||
|
||||
if (itemTable and itemTable.PaintOver) then
|
||||
itemTable.PaintOver(self, itemTable, width, height)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:ExtraPaint(width, height)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
surface.SetDrawColor(0, 0, 0, 85)
|
||||
surface.DrawRect(2, 2, width - 4, height - 4)
|
||||
|
||||
self:ExtraPaint(width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixItemIcon", PANEL, "SpawnIcon")
|
||||
|
||||
PANEL = {}
|
||||
DEFINE_BASECLASS("DFrame")
|
||||
|
||||
AccessorFunc(PANEL, "iconSize", "IconSize", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "bHighlighted", "Highlighted", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetIconSize(64)
|
||||
self:ShowCloseButton(false)
|
||||
self:SetDraggable(true)
|
||||
self:SetSizable(true)
|
||||
self:SetTitle(L"inv")
|
||||
self:Receiver(RECEIVER_NAME, self.ReceiveDrop)
|
||||
|
||||
self.btnMinim:SetVisible(false)
|
||||
self.btnMinim:SetMouseInputEnabled(false)
|
||||
self.btnMaxim:SetVisible(false)
|
||||
self.btnMaxim:SetMouseInputEnabled(false)
|
||||
|
||||
self.panels = {}
|
||||
end
|
||||
|
||||
function PANEL:GetPadding(index)
|
||||
return select(index, self:GetDockPadding())
|
||||
end
|
||||
|
||||
function PANEL:SetTitle(text)
|
||||
if (text == nil) then
|
||||
self.oldPadding = {self:GetDockPadding()}
|
||||
|
||||
self.lblTitle:SetText("")
|
||||
self.lblTitle:SetVisible(false)
|
||||
|
||||
self:DockPadding(5, 5, 5, 5)
|
||||
else
|
||||
if (self.oldPadding) then
|
||||
self:DockPadding(unpack(self.oldPadding))
|
||||
self.oldPadding = nil
|
||||
end
|
||||
|
||||
BaseClass.SetTitle(self, text)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:FitParent(invWidth, invHeight)
|
||||
local parent = self:GetParent()
|
||||
|
||||
if (!IsValid(parent)) then
|
||||
return
|
||||
end
|
||||
|
||||
local width, height = parent:GetSize()
|
||||
local padding = 4
|
||||
local iconSize
|
||||
|
||||
if (invWidth > invHeight) then
|
||||
iconSize = (width - padding * 2) / invWidth
|
||||
elseif (invHeight > invWidth) then
|
||||
iconSize = (height - padding * 2) / invHeight
|
||||
else
|
||||
-- we use height because the titlebar will make it more tall than it is wide
|
||||
iconSize = (height - padding * 2) / invHeight - 4
|
||||
end
|
||||
|
||||
self:SetSize(iconSize * invWidth + padding * 2, iconSize * invHeight + padding * 2)
|
||||
self:SetIconSize(iconSize)
|
||||
end
|
||||
|
||||
function PANEL:OnRemove()
|
||||
if (self.childPanels) then
|
||||
for _, v in ipairs(self.childPanels) do
|
||||
if (v != self) then
|
||||
v:Remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:ViewOnly()
|
||||
self.viewOnly = true
|
||||
|
||||
for _, icon in pairs(self.panels) do
|
||||
icon.OnMousePressed = nil
|
||||
icon.OnMouseReleased = nil
|
||||
icon.doRightClick = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetInventory(inventory, bFitParent)
|
||||
if (inventory.slots) then
|
||||
local invWidth, invHeight = inventory:GetSize()
|
||||
self.invID = inventory:GetID()
|
||||
|
||||
if (IsValid(ix.gui.inv1) and ix.gui.inv1.childPanels and inventory != LocalPlayer():GetCharacter():GetInventory()) then
|
||||
self:SetIconSize(ix.gui.inv1:GetIconSize())
|
||||
self:SetPaintedManually(true)
|
||||
self.bNoBackgroundBlur = true
|
||||
|
||||
ix.gui.inv1.childPanels[#ix.gui.inv1.childPanels + 1] = self
|
||||
elseif (bFitParent) then
|
||||
self:FitParent(invWidth, invHeight)
|
||||
else
|
||||
self:SetSize(self.iconSize, self.iconSize)
|
||||
end
|
||||
|
||||
self:SetGridSize(invWidth, invHeight)
|
||||
|
||||
for x, items in pairs(inventory.slots) do
|
||||
for y, data in pairs(items) do
|
||||
if (!data.id) then continue end
|
||||
|
||||
local item = ix.item.instances[data.id]
|
||||
|
||||
if (item and !IsValid(self.panels[item.id])) then
|
||||
local icon = self:AddIcon(item:GetModel() or "models/props_junk/popcan01a.mdl",
|
||||
x, y, item.width, item.height, item:GetSkin())
|
||||
|
||||
if (IsValid(icon)) then
|
||||
icon:SetHelixTooltip(function(tooltip)
|
||||
ix.hud.PopulateItemTooltip(tooltip, item)
|
||||
end)
|
||||
|
||||
self.panels[item.id] = icon
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetGridSize(w, h)
|
||||
local iconSize = self.iconSize
|
||||
local newWidth = w * iconSize + 8
|
||||
local newHeight = h * iconSize + self:GetPadding(2) + self:GetPadding(4)
|
||||
|
||||
self.gridW = w
|
||||
self.gridH = h
|
||||
|
||||
self:SetSize(newWidth, newHeight)
|
||||
self:SetMinWidth(newWidth)
|
||||
self:SetMinHeight(newHeight)
|
||||
self:BuildSlots()
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout(width, height)
|
||||
BaseClass.PerformLayout(self, width, height)
|
||||
|
||||
if (self.Sizing and self.gridW and self.gridH) then
|
||||
local newWidth = (width - 8) / self.gridW
|
||||
local newHeight = (height - self:GetPadding(2) + self:GetPadding(4)) / self.gridH
|
||||
|
||||
self:SetIconSize((newWidth + newHeight) / 2)
|
||||
self:RebuildItems()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:BuildSlots()
|
||||
local iconSize = self.iconSize
|
||||
|
||||
self.slots = self.slots or {}
|
||||
|
||||
for _, v in ipairs(self.slots) do
|
||||
for _, v2 in ipairs(v) do
|
||||
v2:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.slots = {}
|
||||
|
||||
for x = 1, self.gridW do
|
||||
self.slots[x] = {}
|
||||
|
||||
for y = 1, self.gridH do
|
||||
local slot = self:Add("DPanel")
|
||||
slot:SetZPos(-999)
|
||||
slot.gridX = x
|
||||
slot.gridY = y
|
||||
slot:SetPos((x - 1) * iconSize + 4, (y - 1) * iconSize + self:GetPadding(2))
|
||||
slot:SetSize(iconSize, iconSize)
|
||||
slot.Paint = function(panel, width, height)
|
||||
derma.SkinFunc("PaintInventorySlot", panel, width, height)
|
||||
end
|
||||
|
||||
self.slots[x][y] = slot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:RebuildItems()
|
||||
local iconSize = self.iconSize
|
||||
|
||||
for x = 1, self.gridW do
|
||||
for y = 1, self.gridH do
|
||||
local slot = self.slots[x][y]
|
||||
|
||||
slot:SetPos((x - 1) * iconSize + 4, (y - 1) * iconSize + self:GetPadding(2))
|
||||
slot:SetSize(iconSize, iconSize)
|
||||
end
|
||||
end
|
||||
|
||||
for _, v in pairs(self.panels) do
|
||||
if (IsValid(v)) then
|
||||
v:SetPos(self.slots[v.gridX][v.gridY]:GetPos())
|
||||
v:SetSize(v.gridW * iconSize, v.gridH * iconSize)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:PaintDragPreview(width, height, mouseX, mouseY, itemPanel)
|
||||
local iconSize = self.iconSize
|
||||
local item = itemPanel:GetItemTable()
|
||||
|
||||
if (item) then
|
||||
local inventory = ix.item.inventories[self.invID]
|
||||
local dropX = math.ceil((mouseX - 4 - (itemPanel.gridW - 1) * 32) / iconSize)
|
||||
local dropY = math.ceil((mouseY - self:GetPadding(2) - (itemPanel.gridH - 1) * 32) / iconSize)
|
||||
|
||||
local hoveredPanel = vgui.GetHoveredPanel()
|
||||
|
||||
if (IsValid(hoveredPanel) and hoveredPanel != itemPanel and hoveredPanel.GetItemTable) then
|
||||
local hoveredItem = hoveredPanel:GetItemTable()
|
||||
|
||||
if (hoveredItem) then
|
||||
local info = hoveredItem.functions.combine
|
||||
|
||||
if (info and info.OnCanRun and info.OnCanRun(hoveredItem, {item.id}) != false) then
|
||||
surface.SetDrawColor(ColorAlpha(derma.GetColor("Info", self, Color(200, 0, 0)), 20))
|
||||
surface.DrawRect(
|
||||
hoveredPanel.x,
|
||||
hoveredPanel.y,
|
||||
hoveredPanel:GetWide(),
|
||||
hoveredPanel:GetTall()
|
||||
)
|
||||
|
||||
self.combineItem = hoveredItem
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.combineItem = nil
|
||||
|
||||
-- don't draw grid if we're dragging it out of bounds
|
||||
if (inventory) then
|
||||
local invWidth, invHeight = inventory:GetSize()
|
||||
|
||||
if (dropX < 1 or dropY < 1 or
|
||||
dropX + itemPanel.gridW - 1 > invWidth or
|
||||
dropY + itemPanel.gridH - 1 > invHeight) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local bEmpty = true
|
||||
|
||||
for x = 0, itemPanel.gridW - 1 do
|
||||
for y = 0, itemPanel.gridH - 1 do
|
||||
local x2 = dropX + x
|
||||
local y2 = dropY + y
|
||||
|
||||
bEmpty = self:IsEmpty(x2, y2, itemPanel)
|
||||
|
||||
if (!bEmpty) then
|
||||
-- no need to iterate further since we know something is blocking the hovered grid cells, break through both loops
|
||||
goto finish
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
::finish::
|
||||
local previewColor = ColorAlpha(derma.GetColor(bEmpty and "Success" or "Error", self, Color(200, 0, 0)), 20)
|
||||
|
||||
surface.SetDrawColor(previewColor)
|
||||
surface.DrawRect(
|
||||
(dropX - 1) * iconSize + 4,
|
||||
(dropY - 1) * iconSize + self:GetPadding(2),
|
||||
itemPanel:GetWide(),
|
||||
itemPanel:GetTall()
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:PaintOver(width, height)
|
||||
local panel = self.previewPanel
|
||||
|
||||
if (IsValid(panel)) then
|
||||
local itemPanel = (dragndrop.GetDroppable() or {})[1]
|
||||
|
||||
if (IsValid(itemPanel)) then
|
||||
self:PaintDragPreview(width, height, self.previewX, self.previewY, itemPanel)
|
||||
end
|
||||
end
|
||||
|
||||
self.previewPanel = nil
|
||||
end
|
||||
|
||||
function PANEL:IsEmpty(x, y, this)
|
||||
return (self.slots[x] and self.slots[x][y]) and (!IsValid(self.slots[x][y].item) or self.slots[x][y].item == this)
|
||||
end
|
||||
|
||||
function PANEL:IsAllEmpty(x, y, width, height, this)
|
||||
for x2 = 0, width - 1 do
|
||||
for y2 = 0, height - 1 do
|
||||
if (!self:IsEmpty(x + x2, y + y2, this)) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function PANEL:OnTransfer(oldX, oldY, x, y, oldInventory, noSend)
|
||||
local inventories = ix.item.inventories
|
||||
local inventory = inventories[oldInventory.invID]
|
||||
local inventory2 = inventories[self.invID]
|
||||
local item
|
||||
|
||||
if (inventory) then
|
||||
item = inventory:GetItemAt(oldX, oldY)
|
||||
|
||||
if (!item) then
|
||||
return false
|
||||
end
|
||||
|
||||
if (hook.Run("CanTransferItem", item, inventories[oldInventory.invID], inventories[self.invID]) == false) then
|
||||
return false, "notAllowed"
|
||||
end
|
||||
|
||||
if (item.CanTransfer and
|
||||
item:CanTransfer(inventory, inventory != inventory2 and inventory2 or nil) == false) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if (!noSend) then
|
||||
net.Start("ixInventoryMove")
|
||||
net.WriteUInt(oldX, 6)
|
||||
net.WriteUInt(oldY, 6)
|
||||
net.WriteUInt(x, 6)
|
||||
net.WriteUInt(y, 6)
|
||||
net.WriteUInt(oldInventory.invID, 32)
|
||||
net.WriteUInt(self != oldInventory and self.invID or oldInventory.invID, 32)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
if (inventory) then
|
||||
inventory.slots[oldX][oldY] = nil
|
||||
end
|
||||
|
||||
if (item and inventory2) then
|
||||
inventory2.slots[x] = inventory2.slots[x] or {}
|
||||
inventory2.slots[x][y] = item
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:AddIcon(model, x, y, w, h, skin)
|
||||
local iconSize = self.iconSize
|
||||
|
||||
w = w or 1
|
||||
h = h or 1
|
||||
|
||||
if (self.slots[x] and self.slots[x][y]) then
|
||||
local panel = self:Add("ixItemIcon")
|
||||
panel:SetSize(w * iconSize, h * iconSize)
|
||||
panel:SetZPos(999)
|
||||
panel:InvalidateLayout(true)
|
||||
panel:SetModel(model, skin)
|
||||
panel:SetPos(self.slots[x][y]:GetPos())
|
||||
panel.gridX = x
|
||||
panel.gridY = y
|
||||
panel.gridW = w
|
||||
panel.gridH = h
|
||||
|
||||
local inventory = ix.item.inventories[self.invID]
|
||||
|
||||
if (!inventory) then
|
||||
return
|
||||
end
|
||||
|
||||
local itemTable = inventory:GetItemAt(panel.gridX, panel.gridY)
|
||||
|
||||
panel:SetInventoryID(inventory:GetID())
|
||||
panel:SetItemTable(itemTable)
|
||||
|
||||
if (self.panels[itemTable:GetID()]) then
|
||||
self.panels[itemTable:GetID()]:Remove()
|
||||
end
|
||||
|
||||
if (itemTable.exRender) then
|
||||
panel.Icon:SetVisible(false)
|
||||
panel.ExtraPaint = function(this, panelX, panelY)
|
||||
local exIcon = ikon:GetIcon(itemTable.uniqueID)
|
||||
if (exIcon) then
|
||||
surface.SetMaterial(exIcon)
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.DrawTexturedRect(0, 0, panelX, panelY)
|
||||
else
|
||||
ikon:renderIcon(
|
||||
itemTable.uniqueID,
|
||||
itemTable.width,
|
||||
itemTable.height,
|
||||
itemTable:GetModel(),
|
||||
itemTable.iconCam
|
||||
)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- yeah..
|
||||
RenderNewIcon(panel, itemTable)
|
||||
end
|
||||
|
||||
panel.slots = {}
|
||||
|
||||
for i = 0, w - 1 do
|
||||
for i2 = 0, h - 1 do
|
||||
local slot = self.slots[x + i] and self.slots[x + i][y + i2]
|
||||
|
||||
if (IsValid(slot)) then
|
||||
slot.item = panel
|
||||
panel.slots[#panel.slots + 1] = slot
|
||||
else
|
||||
for _, v in ipairs(panel.slots) do
|
||||
v.item = nil
|
||||
end
|
||||
|
||||
panel:Remove()
|
||||
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return panel
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:ReceiveDrop(panels, bDropped, menuIndex, x, y)
|
||||
local panel = panels[1]
|
||||
|
||||
if (!IsValid(panel)) then
|
||||
self.previewPanel = nil
|
||||
return
|
||||
end
|
||||
|
||||
if (bDropped) then
|
||||
local inventory = ix.item.inventories[self.invID]
|
||||
|
||||
if (inventory and panel.OnDrop) then
|
||||
local dropX = math.ceil((x - 4 - (panel.gridW - 1) * 32) / self.iconSize)
|
||||
local dropY = math.ceil((y - self:GetPadding(2) - (panel.gridH - 1) * 32) / self.iconSize)
|
||||
|
||||
panel:OnDrop(true, self, inventory, dropX, dropY)
|
||||
end
|
||||
|
||||
self.previewPanel = nil
|
||||
else
|
||||
self.previewPanel = panel
|
||||
self.previewX = x
|
||||
self.previewY = y
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixInventory", PANEL, "DFrame")
|
||||
|
||||
hook.Add("CreateMenuButtons", "ixInventory", function(tabs)
|
||||
if (hook.Run("CanPlayerViewInventory") == false) then
|
||||
return
|
||||
end
|
||||
|
||||
tabs["inv"] = {
|
||||
bDefault = true,
|
||||
Create = function(info, container)
|
||||
local canvas = container:Add("DTileLayout")
|
||||
local canvasLayout = canvas.PerformLayout
|
||||
canvas.PerformLayout = nil -- we'll layout after we add the panels instead of each time one is added
|
||||
canvas:SetBorder(0)
|
||||
canvas:SetSpaceX(2)
|
||||
canvas:SetSpaceY(2)
|
||||
canvas:Dock(FILL)
|
||||
|
||||
ix.gui.menuInventoryContainer = canvas
|
||||
|
||||
local panel = canvas:Add("ixInventory")
|
||||
panel:SetPos(0, 0)
|
||||
panel:SetDraggable(false)
|
||||
panel:SetSizable(false)
|
||||
panel:SetTitle(nil)
|
||||
panel.bNoBackgroundBlur = true
|
||||
panel.childPanels = {}
|
||||
|
||||
local inventory = LocalPlayer():GetCharacter():GetInventory()
|
||||
|
||||
if (inventory) then
|
||||
panel:SetInventory(inventory)
|
||||
end
|
||||
|
||||
ix.gui.inv1 = panel
|
||||
|
||||
if (ix.option.Get("openBags", true)) then
|
||||
for _, v in pairs(inventory:GetItems()) do
|
||||
if (!v.isBag) then
|
||||
continue
|
||||
end
|
||||
|
||||
v.functions.View.OnClick(v)
|
||||
end
|
||||
end
|
||||
|
||||
canvas.PerformLayout = canvasLayout
|
||||
canvas:Layout()
|
||||
end
|
||||
}
|
||||
end)
|
||||
|
||||
hook.Add("PostRenderVGUI", "ixInvHelper", function()
|
||||
local pnl = ix.gui.inv1
|
||||
|
||||
hook.Run("PostDrawInventory", pnl)
|
||||
end)
|
||||
501
gamemodes/helix/gamemode/core/derma/cl_menu.lua
Normal file
501
gamemodes/helix/gamemode/core/derma/cl_menu.lua
Normal file
@@ -0,0 +1,501 @@
|
||||
--[[
|
||||
| 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 animationTime = 1
|
||||
local matrixZScale = Vector(1, 1, 0.0001)
|
||||
|
||||
DEFINE_BASECLASS("ixSubpanelParent")
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "bCharacterOverview", "CharacterOverview", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
if (IsValid(ix.gui.menu)) then
|
||||
ix.gui.menu:Remove()
|
||||
end
|
||||
|
||||
ix.gui.menu = self
|
||||
|
||||
-- properties
|
||||
self.manualChildren = {}
|
||||
self.noAnchor = CurTime() + 0.4
|
||||
self.anchorMode = true
|
||||
self.rotationOffset = Angle(0, 180, 0)
|
||||
self.projectedTexturePosition = Vector(0, 0, 6)
|
||||
self.projectedTextureRotation = Angle(-45, 60, 0)
|
||||
|
||||
self.bCharacterOverview = false
|
||||
self.bOverviewOut = false
|
||||
self.overviewFraction = 0
|
||||
|
||||
self.currentAlpha = 0
|
||||
self.currentBlur = 0
|
||||
|
||||
-- setup
|
||||
self:SetPadding(ScreenScale(16), true)
|
||||
self:SetSize(ScrW(), ScrH())
|
||||
self:SetPos(0, 0)
|
||||
self:SetLeftOffset(self:GetWide() * 0.25 + self:GetPadding())
|
||||
|
||||
-- main button panel
|
||||
self.buttons = self:Add("Panel")
|
||||
self.buttons:SetSize(self:GetWide() * 0.25, self:GetTall() - self:GetPadding() * 2)
|
||||
self.buttons:Dock(LEFT)
|
||||
self.buttons:SetPaintedManually(true)
|
||||
|
||||
local close = self.buttons:Add("ixMenuButton")
|
||||
close:SetText("return")
|
||||
close:SizeToContents()
|
||||
close:Dock(BOTTOM)
|
||||
close.DoClick = function()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
local characters = self.buttons:Add("ixMenuButton")
|
||||
characters:SetText("characters")
|
||||
characters:SizeToContents()
|
||||
characters:Dock(BOTTOM)
|
||||
characters.DoClick = function()
|
||||
self:Remove()
|
||||
vgui.Create("ixCharMenu")
|
||||
end
|
||||
|
||||
-- @todo make a better way to avoid clicks in the padding PLEASE
|
||||
self.guard = self:Add("Panel")
|
||||
self.guard:SetPos(0, 0)
|
||||
self.guard:SetSize(self:GetPadding(), self:GetTall())
|
||||
|
||||
-- tabs
|
||||
self.tabs = self.buttons:Add("Panel")
|
||||
self.tabs.buttons = {}
|
||||
self.tabs:Dock(FILL)
|
||||
self:PopulateTabs()
|
||||
|
||||
self:MakePopup()
|
||||
self:OnOpened()
|
||||
end
|
||||
|
||||
function PANEL:OnOpened()
|
||||
self:SetAlpha(0)
|
||||
|
||||
self:CreateAnimation(animationTime, {
|
||||
target = {currentAlpha = 255},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.currentAlpha)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:GetActiveTab()
|
||||
return (self:GetActiveSubpanel() or {}).subpanelName
|
||||
end
|
||||
|
||||
function PANEL:TransitionSubpanel(id)
|
||||
local lastSubpanel = self:GetActiveSubpanel()
|
||||
|
||||
-- don't transition to the same panel
|
||||
if (IsValid(lastSubpanel) and lastSubpanel.subpanelID == id) then
|
||||
return
|
||||
end
|
||||
|
||||
local subpanel = self:GetSubpanel(id)
|
||||
|
||||
if (IsValid(subpanel)) then
|
||||
if (!subpanel.bPopulated) then
|
||||
-- we need to set the size of the subpanel if it's a section since it will be 0, 0
|
||||
if (subpanel.sectionParent) then
|
||||
subpanel:SetSize(self:GetStandardSubpanelSize())
|
||||
end
|
||||
|
||||
local info = subpanel.info
|
||||
subpanel.Paint = nil
|
||||
|
||||
if (istable(info) and info.Create) then
|
||||
info:Create(subpanel)
|
||||
elseif (isfunction(info)) then
|
||||
info(subpanel)
|
||||
end
|
||||
|
||||
hook.Run("MenuSubpanelCreated", subpanel.subpanelName, subpanel)
|
||||
subpanel.bPopulated = true
|
||||
end
|
||||
|
||||
-- only play whoosh sound only when the menu was already open
|
||||
if (IsValid(lastSubpanel)) then
|
||||
LocalPlayer():EmitSound("Helix.Whoosh")
|
||||
end
|
||||
|
||||
self:SetActiveSubpanel(id)
|
||||
end
|
||||
|
||||
subpanel = self:GetActiveSubpanel()
|
||||
|
||||
local info = subpanel.info
|
||||
local bHideBackground = istable(info) and (info.bHideBackground != nil and info.bHideBackground or false) or false
|
||||
|
||||
if (bHideBackground) then
|
||||
self:HideBackground()
|
||||
else
|
||||
self:ShowBackground()
|
||||
end
|
||||
|
||||
-- call hooks if we've changed subpanel
|
||||
if (IsValid(lastSubpanel) and istable(lastSubpanel.info) and lastSubpanel.info.OnDeselected) then
|
||||
lastSubpanel.info:OnDeselected(lastSubpanel)
|
||||
end
|
||||
|
||||
if (IsValid(subpanel) and istable(subpanel.info) and subpanel.info.OnSelected) then
|
||||
subpanel.info:OnSelected(subpanel)
|
||||
end
|
||||
|
||||
ix.gui.lastMenuTab = id
|
||||
end
|
||||
|
||||
function PANEL:SetCharacterOverview(bValue, length)
|
||||
bValue = tobool(bValue)
|
||||
length = length or animationTime
|
||||
|
||||
if (bValue) then
|
||||
if (!IsValid(self.projectedTexture)) then
|
||||
self.projectedTexture = ProjectedTexture()
|
||||
end
|
||||
|
||||
local faction = ix.faction.indices[LocalPlayer():Team()]
|
||||
local color = faction and faction.color or color_white
|
||||
|
||||
self.projectedTexture:SetEnableShadows(false)
|
||||
self.projectedTexture:SetNearZ(12)
|
||||
self.projectedTexture:SetFarZ(64)
|
||||
self.projectedTexture:SetFOV(90)
|
||||
self.projectedTexture:SetColor(color)
|
||||
self.projectedTexture:SetTexture("effects/flashlight/soft")
|
||||
|
||||
self:CreateAnimation(length, {
|
||||
index = 3,
|
||||
target = {overviewFraction = 1},
|
||||
easing = "outQuint",
|
||||
bIgnoreConfig = true
|
||||
})
|
||||
|
||||
self.bOverviewOut = false
|
||||
self.bCharacterOverview = true
|
||||
else
|
||||
self:CreateAnimation(length, {
|
||||
index = 3,
|
||||
target = {overviewFraction = 0},
|
||||
easing = "outQuint",
|
||||
bIgnoreConfig = true,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
panel.bCharacterOverview = false
|
||||
|
||||
if (IsValid(panel.projectedTexture)) then
|
||||
panel.projectedTexture:Remove()
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
self.bOverviewOut = true
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:GetOverviewInfo(origin, angles, fov)
|
||||
local originAngles = Angle(0, angles.yaw, angles.roll)
|
||||
local target = LocalPlayer():GetObserverTarget()
|
||||
local fraction = self.overviewFraction
|
||||
local bDrawPlayer = ((fraction > 0.2) or (!self.bOverviewOut and (fraction > 0.2))) and !IsValid(target)
|
||||
local forward = originAngles:Forward() * 58 - originAngles:Right() * 16
|
||||
forward.z = 0
|
||||
|
||||
local newOrigin
|
||||
|
||||
if (IsValid(target)) then
|
||||
newOrigin = target:GetPos() + forward
|
||||
else
|
||||
newOrigin = origin - LocalPlayer():OBBCenter() * 0.6 + forward
|
||||
end
|
||||
|
||||
local newAngles = originAngles + self.rotationOffset
|
||||
newAngles.pitch = 5
|
||||
newAngles.roll = 0
|
||||
|
||||
return LerpVector(fraction, origin, newOrigin), LerpAngle(fraction, angles, newAngles), Lerp(fraction, fov, 90), bDrawPlayer
|
||||
end
|
||||
|
||||
function PANEL:HideBackground()
|
||||
self:CreateAnimation(animationTime, {
|
||||
index = 2,
|
||||
target = {currentBlur = 0},
|
||||
easing = "outQuint"
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:ShowBackground()
|
||||
self:CreateAnimation(animationTime, {
|
||||
index = 2,
|
||||
target = {currentBlur = 1},
|
||||
easing = "outQuint"
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:GetStandardSubpanelSize()
|
||||
return ScrW() * 0.75 - self:GetPadding() * 3, ScrH() - self:GetPadding() * 2
|
||||
end
|
||||
|
||||
function PANEL:SetupTab(name, info, sectionParent)
|
||||
local bTable = istable(info)
|
||||
local buttonColor = (bTable and info.buttonColor) or (ix.config.Get("color") or Color(140, 140, 140, 255))
|
||||
local bDefault = (bTable and info.bDefault) or false
|
||||
local qualifiedName = sectionParent and (sectionParent.name .. "/" .. name) or name
|
||||
|
||||
-- setup subpanels without populating them so we can retain the order
|
||||
local subpanel = self:AddSubpanel(qualifiedName, true)
|
||||
local id = subpanel.subpanelID
|
||||
subpanel.info = info
|
||||
subpanel.sectionParent = sectionParent and qualifiedName
|
||||
subpanel:SetPaintedManually(true)
|
||||
subpanel:SetTitle(nil)
|
||||
|
||||
if (sectionParent) then
|
||||
-- hide section subpanels if they haven't been populated to seeing more subpanels than necessary
|
||||
-- fly by as you navigate tabs in the menu
|
||||
subpanel:SetSize(0, 0)
|
||||
else
|
||||
subpanel:SetSize(self:GetStandardSubpanelSize())
|
||||
|
||||
-- this is called while the subpanel has not been populated
|
||||
subpanel.Paint = function(panel, width, height)
|
||||
derma.SkinFunc("PaintPlaceholderPanel", panel, width, height)
|
||||
end
|
||||
end
|
||||
|
||||
local button
|
||||
|
||||
if (sectionParent) then
|
||||
button = sectionParent:AddSection(L(name))
|
||||
name = qualifiedName
|
||||
else
|
||||
button = self.tabs:Add("ixMenuSelectionButton")
|
||||
button:SetText(L(name))
|
||||
button:SizeToContents()
|
||||
button:Dock(TOP)
|
||||
button:SetButtonList(self.tabs.buttons)
|
||||
button:SetBackgroundColor(buttonColor)
|
||||
end
|
||||
|
||||
button.name = name
|
||||
button.id = id
|
||||
button.OnSelected = function()
|
||||
self:TransitionSubpanel(id)
|
||||
end
|
||||
|
||||
if (bTable and info.PopulateTabButton) then
|
||||
info:PopulateTabButton(button)
|
||||
end
|
||||
|
||||
-- don't allow sections in sections
|
||||
if (sectionParent or !bTable or !info.Sections) then
|
||||
return bDefault, button, subpanel
|
||||
end
|
||||
|
||||
-- create button sections
|
||||
for sectionName, sectionInfo in pairs(info.Sections) do
|
||||
self:SetupTab(sectionName, sectionInfo, button)
|
||||
end
|
||||
|
||||
return bDefault, button, subpanel
|
||||
end
|
||||
|
||||
function PANEL:PopulateTabs()
|
||||
local default
|
||||
local tabs = {}
|
||||
|
||||
hook.Run("CreateMenuButtons", tabs)
|
||||
|
||||
for name, info in SortedPairs(tabs) do
|
||||
local bDefault, button = self:SetupTab(name, info)
|
||||
|
||||
if (bDefault) then
|
||||
default = button
|
||||
end
|
||||
end
|
||||
|
||||
if (ix.gui.lastMenuTab) then
|
||||
for i = 1, #self.tabs.buttons do
|
||||
local button = self.tabs.buttons[i]
|
||||
|
||||
if (button.id == ix.gui.lastMenuTab) then
|
||||
default = button
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (!IsValid(default) and #self.tabs.buttons > 0) then
|
||||
default = self.tabs.buttons[1]
|
||||
end
|
||||
|
||||
if (IsValid(default)) then
|
||||
default:SetSelected(true)
|
||||
self:SetActiveSubpanel(default.id, 0)
|
||||
end
|
||||
|
||||
self.buttons:MoveToFront()
|
||||
self.guard:MoveToBefore(self.buttons)
|
||||
end
|
||||
|
||||
function PANEL:AddManuallyPaintedChild(panel)
|
||||
panel:SetParent(self)
|
||||
panel:SetPaintedManually(panel)
|
||||
|
||||
self.manualChildren[#self.manualChildren + 1] = panel
|
||||
end
|
||||
|
||||
function PANEL:OnKeyCodePressed(key)
|
||||
self.noAnchor = CurTime() + 0.5
|
||||
|
||||
if (key == KEY_TAB) then
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
if (IsValid(self.projectedTexture)) then
|
||||
local forward = LocalPlayer():GetForward()
|
||||
forward.z = 0
|
||||
|
||||
local right = LocalPlayer():GetRight()
|
||||
right.z = 0
|
||||
|
||||
self.projectedTexture:SetBrightness(self.overviewFraction * 4)
|
||||
self.projectedTexture:SetPos(LocalPlayer():GetPos() + right * 16 - forward * 8 + self.projectedTexturePosition)
|
||||
self.projectedTexture:SetAngles(forward:Angle() + self.projectedTextureRotation)
|
||||
self.projectedTexture:Update()
|
||||
end
|
||||
|
||||
if (self.bClosing) then
|
||||
return
|
||||
end
|
||||
|
||||
local bTabDown = input.IsKeyDown(KEY_TAB)
|
||||
|
||||
if (bTabDown and (self.noAnchor or CurTime() + 0.4) < CurTime() and self.anchorMode) then
|
||||
self.anchorMode = false
|
||||
surface.PlaySound("buttons/lightswitch2.wav")
|
||||
end
|
||||
|
||||
if ((!self.anchorMode and !bTabDown) or gui.IsGameUIVisible()) then
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("PaintMenuBackground", self, width, height, self.currentBlur)
|
||||
|
||||
local bShouldScale = self.currentAlpha != 255
|
||||
|
||||
if (bShouldScale) then
|
||||
local currentScale = Lerp(self.currentAlpha / 255, 0.9, 1)
|
||||
local matrix = Matrix()
|
||||
|
||||
matrix:Scale(matrixZScale * currentScale)
|
||||
matrix:Translate(Vector(
|
||||
ScrW() * 0.5 - (ScrW() * currentScale * 0.5),
|
||||
ScrH() * 0.5 - (ScrH() * currentScale * 0.5),
|
||||
1
|
||||
))
|
||||
|
||||
cam.PushModelMatrix(matrix)
|
||||
end
|
||||
|
||||
BaseClass.Paint(self, width, height)
|
||||
self:PaintSubpanels(width, height)
|
||||
self.buttons:PaintManual()
|
||||
|
||||
for i = 1, #self.manualChildren do
|
||||
self.manualChildren[i]:PaintManual()
|
||||
end
|
||||
|
||||
if (IsValid(ix.gui.inv1) and ix.gui.inv1.childPanels) then
|
||||
for i = 1, #ix.gui.inv1.childPanels do
|
||||
local panel = ix.gui.inv1.childPanels[i]
|
||||
|
||||
if (IsValid(panel)) then
|
||||
panel:PaintManual()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (bShouldScale) then
|
||||
cam.PopModelMatrix()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
self.guard:SetSize(self.tabs:GetWide() + self:GetPadding() * 2, self:GetTall())
|
||||
end
|
||||
|
||||
function PANEL:Remove()
|
||||
self.bClosing = true
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
self:SetCharacterOverview(false, animationTime * 0.5)
|
||||
|
||||
-- remove input from opened child panels since they grab focus
|
||||
if (IsValid(ix.gui.inv1) and ix.gui.inv1.childPanels) then
|
||||
for i = 1, #ix.gui.inv1.childPanels do
|
||||
local panel = ix.gui.inv1.childPanels[i]
|
||||
|
||||
if (IsValid(panel)) then
|
||||
panel:SetMouseInputEnabled(false)
|
||||
panel:SetKeyboardInputEnabled(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
CloseDermaMenus()
|
||||
gui.EnableScreenClicker(false)
|
||||
|
||||
self:CreateAnimation(animationTime * 0.5, {
|
||||
index = 2,
|
||||
target = {currentBlur = 0},
|
||||
easing = "outQuint"
|
||||
})
|
||||
|
||||
self:CreateAnimation(animationTime * 0.5, {
|
||||
target = {currentAlpha = 0},
|
||||
easing = "outQuint",
|
||||
|
||||
-- we don't animate the blur because blurring doesn't draw things
|
||||
-- with amount < 1 very well, resulting in jarring transition
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.currentAlpha)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
if (IsValid(panel.projectedTexture)) then
|
||||
panel.projectedTexture:Remove()
|
||||
end
|
||||
|
||||
BaseClass.Remove(panel)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
vgui.Register("ixMenu", PANEL, "ixSubpanelParent")
|
||||
|
||||
if (IsValid(ix.gui.menu)) then
|
||||
ix.gui.menu:Remove()
|
||||
end
|
||||
|
||||
ix.gui.lastMenuTab = nil
|
||||
305
gamemodes/helix/gamemode/core/derma/cl_menubutton.lua
Normal file
305
gamemodes/helix/gamemode/core/derma/cl_menubutton.lua
Normal file
@@ -0,0 +1,305 @@
|
||||
--[[
|
||||
| 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 buttonPadding = ScreenScale(14) * 0.5
|
||||
local animationTime = 0.5
|
||||
|
||||
-- base menu button
|
||||
DEFINE_BASECLASS("DButton")
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
|
||||
AccessorFunc(PANEL, "backgroundAlpha", "BackgroundAlpha")
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetFont("ixMenuButtonFont")
|
||||
self:SetTextColor(color_white)
|
||||
self:SetPaintBackground(false)
|
||||
self:SetContentAlignment(4)
|
||||
self:SetTextInset(buttonPadding, 0)
|
||||
|
||||
self.padding = {32, 12, 32, 12} -- left, top, right, bottom
|
||||
self.backgroundColor = Color(0, 0, 0)
|
||||
self.backgroundAlpha = 128
|
||||
self.currentBackgroundAlpha = 0
|
||||
end
|
||||
|
||||
function PANEL:GetPadding()
|
||||
return self.padding
|
||||
end
|
||||
|
||||
function PANEL:SetPadding(left, top, right, bottom)
|
||||
self.padding = {
|
||||
left or self.padding[1],
|
||||
top or self.padding[2],
|
||||
right or self.padding[3],
|
||||
bottom or self.padding[4]
|
||||
}
|
||||
end
|
||||
|
||||
function PANEL:SetText(text, noTranslation)
|
||||
BaseClass.SetText(self, noTranslation and text:utf8upper() or L(text):utf8upper())
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
BaseClass.SizeToContents(self)
|
||||
|
||||
local width, height = self:GetSize()
|
||||
self:SetSize(width + self.padding[1] + self.padding[3], height + self.padding[2] + self.padding[4])
|
||||
end
|
||||
|
||||
function PANEL:PaintBackground(width, height)
|
||||
surface.SetDrawColor(ColorAlpha(self.backgroundColor, self.currentBackgroundAlpha))
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
self:PaintBackground(width, height)
|
||||
BaseClass.Paint(self, width, height)
|
||||
end
|
||||
|
||||
function PANEL:SetTextColorInternal(color)
|
||||
BaseClass.SetTextColor(self, color)
|
||||
self:SetFGColor(color)
|
||||
end
|
||||
|
||||
function PANEL:SetTextColor(color)
|
||||
self:SetTextColorInternal(color)
|
||||
self.color = color
|
||||
end
|
||||
|
||||
function PANEL:SetDisabled(bValue)
|
||||
local color = self.color
|
||||
|
||||
if (bValue) then
|
||||
self:SetTextColorInternal(Color(math.max(color.r - 60, 0), math.max(color.g - 60, 0), math.max(color.b - 60, 0)))
|
||||
else
|
||||
self:SetTextColorInternal(color)
|
||||
end
|
||||
|
||||
BaseClass.SetDisabled(self, bValue)
|
||||
end
|
||||
|
||||
function PANEL:OnCursorEntered()
|
||||
if (self:GetDisabled()) then
|
||||
return
|
||||
end
|
||||
|
||||
local color = self:GetTextColor()
|
||||
self:SetTextColorInternal(Color(math.max(color.r - 25, 0), math.max(color.g - 25, 0), math.max(color.b - 25, 0)))
|
||||
|
||||
self:CreateAnimation(0.15, {
|
||||
target = {currentBackgroundAlpha = self.backgroundAlpha}
|
||||
})
|
||||
|
||||
LocalPlayer():EmitSound("Helix.Rollover")
|
||||
end
|
||||
|
||||
function PANEL:OnCursorExited()
|
||||
if (self:GetDisabled()) then
|
||||
return
|
||||
end
|
||||
|
||||
if (self.color) then
|
||||
self:SetTextColor(self.color)
|
||||
else
|
||||
self:SetTextColor(color_white)
|
||||
end
|
||||
|
||||
self:CreateAnimation(0.15, {
|
||||
target = {currentBackgroundAlpha = 0}
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed(code)
|
||||
if (self:GetDisabled()) then
|
||||
return
|
||||
end
|
||||
|
||||
if (self.color) then
|
||||
self:SetTextColor(self.color)
|
||||
else
|
||||
self:SetTextColor(ix.config.Get("color"))
|
||||
end
|
||||
|
||||
LocalPlayer():EmitSound("Helix.Press")
|
||||
|
||||
if (code == MOUSE_LEFT and self.DoClick) then
|
||||
self:DoClick(self)
|
||||
elseif (code == MOUSE_RIGHT and self.DoRightClick) then
|
||||
self:DoRightClick(self)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnMouseReleased(key)
|
||||
if (self:GetDisabled()) then
|
||||
return
|
||||
end
|
||||
|
||||
if (self.color) then
|
||||
self:SetTextColor(self.color)
|
||||
else
|
||||
self:SetTextColor(color_white)
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixMenuButton", PANEL, "DButton")
|
||||
|
||||
-- selection menu button
|
||||
DEFINE_BASECLASS("ixMenuButton")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
|
||||
AccessorFunc(PANEL, "selected", "Selected", FORCE_BOOL)
|
||||
AccessorFunc(PANEL, "buttonList", "ButtonList")
|
||||
|
||||
function PANEL:Init()
|
||||
self.backgroundColor = color_white
|
||||
self.selected = false
|
||||
self.buttonList = {}
|
||||
self.sectionPanel = nil -- sub-sections this button has; created only if it has any sections
|
||||
end
|
||||
|
||||
function PANEL:PaintBackground(width, height)
|
||||
local alpha = self.selected and 255 or self.currentBackgroundAlpha
|
||||
|
||||
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, ColorAlpha(self.backgroundColor, alpha))
|
||||
end
|
||||
|
||||
function PANEL:SetSelected(bValue, bSelectedSection)
|
||||
self.selected = bValue
|
||||
|
||||
if (bValue) then
|
||||
self:OnSelected()
|
||||
|
||||
if (self.sectionPanel) then
|
||||
self.sectionPanel:Show()
|
||||
elseif (self.sectionParent) then
|
||||
self.sectionParent.sectionPanel:Show()
|
||||
end
|
||||
elseif (self.sectionPanel and self.sectionPanel:IsVisible() and !bSelectedSection) then
|
||||
self.sectionPanel:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetButtonList(list, bNoAdd)
|
||||
if (!bNoAdd) then
|
||||
list[#list + 1] = self
|
||||
end
|
||||
|
||||
self.buttonList = list
|
||||
end
|
||||
|
||||
function PANEL:GetSectionPanel()
|
||||
return self.sectionPanel
|
||||
end
|
||||
|
||||
function PANEL:AddSection(name)
|
||||
if (!IsValid(self.sectionPanel)) then
|
||||
-- add section panel to regular button list
|
||||
self.sectionPanel = vgui.Create("ixMenuSelectionList", self:GetParent())
|
||||
self.sectionPanel:Dock(self:GetDock())
|
||||
self.sectionPanel:SetParentButton(self)
|
||||
end
|
||||
|
||||
return self.sectionPanel:AddButton(name, self.buttonList)
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed(key)
|
||||
for _, v in pairs(self.buttonList) do
|
||||
if (IsValid(v) and v != self) then
|
||||
v:SetSelected(false, self.sectionParent == v)
|
||||
end
|
||||
end
|
||||
|
||||
self:SetSelected(true)
|
||||
BaseClass.OnMousePressed(self, key)
|
||||
end
|
||||
|
||||
function PANEL:OnSelected()
|
||||
end
|
||||
|
||||
vgui.Register("ixMenuSelectionButton", PANEL, "ixMenuButton")
|
||||
|
||||
-- collapsable list for menu button sections
|
||||
PANEL = {}
|
||||
AccessorFunc(PANEL, "parent", "ParentButton")
|
||||
|
||||
function PANEL:Init()
|
||||
self.parent = nil -- button that is responsible for controlling this list
|
||||
self.height = 0
|
||||
self.targetHeight = 0
|
||||
|
||||
self:DockPadding(0, 1, 0, 1)
|
||||
self:SetVisible(false)
|
||||
self:SetTall(0)
|
||||
end
|
||||
|
||||
function PANEL:AddButton(name, buttonList)
|
||||
assert(IsValid(self.parent), "attempted to add button to ixMenuSelectionList without a ParentButton")
|
||||
assert(buttonList ~= nil, "attempted to add button to ixMenuSelectionList without a buttonList")
|
||||
|
||||
local button = self:Add("ixMenuSelectionButton")
|
||||
button.sectionParent = self.parent
|
||||
button:SetTextInset(buttonPadding * 2, 0)
|
||||
button:SetPadding(nil, 8, nil, 8)
|
||||
button:SetFont("ixMenuButtonFontSmall")
|
||||
button:Dock(TOP)
|
||||
button:SetText(name)
|
||||
button:SizeToContents()
|
||||
button:SetButtonList(buttonList)
|
||||
button:SetBackgroundColor(self.parent:GetBackgroundColor())
|
||||
|
||||
self.targetHeight = self.targetHeight + button:GetTall()
|
||||
return button
|
||||
end
|
||||
|
||||
function PANEL:Show()
|
||||
self:SetVisible(true)
|
||||
|
||||
self:CreateAnimation(animationTime, {
|
||||
index = 1,
|
||||
target = {
|
||||
height = self.targetHeight + 2 -- +2 for padding
|
||||
},
|
||||
easing = "outQuart",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetTall(panel.height)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:Hide()
|
||||
self:CreateAnimation(animationTime, {
|
||||
index = 1,
|
||||
target = {
|
||||
height = 0
|
||||
},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetTall(panel.height)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
panel:SetVisible(false)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
surface.SetDrawColor(Color(255, 255, 255, 33))
|
||||
surface.DrawRect(0, 0, width, 1)
|
||||
surface.DrawRect(0, height - 1, width, 1)
|
||||
end
|
||||
|
||||
vgui.Register("ixMenuSelectionList", PANEL, "Panel")
|
||||
130
gamemodes/helix/gamemode/core/derma/cl_modelpanel.lua
Normal file
130
gamemodes/helix/gamemode/core/derma/cl_modelpanel.lua
Normal file
@@ -0,0 +1,130 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
DEFINE_BASECLASS("DModelPanel")
|
||||
|
||||
local PANEL = {}
|
||||
local MODEL_ANGLE = Angle(0, 45, 0)
|
||||
|
||||
function PANEL:Init()
|
||||
self.brightness = 1
|
||||
self:SetCursor("none")
|
||||
end
|
||||
|
||||
function PANEL:SetModel(model, skin, bodygroups)
|
||||
if (IsValid(self.Entity)) then
|
||||
self.Entity:Remove()
|
||||
self.Entity = nil
|
||||
end
|
||||
|
||||
if (!ClientsideModel) then
|
||||
return
|
||||
end
|
||||
|
||||
local entity = ClientsideModel(model, RENDERGROUP_OPAQUE)
|
||||
|
||||
if (!IsValid(entity)) then
|
||||
return
|
||||
end
|
||||
|
||||
entity:SetNoDraw(true)
|
||||
entity:SetIK(false)
|
||||
|
||||
if (skin) then
|
||||
entity:SetSkin(skin)
|
||||
end
|
||||
|
||||
if (isstring(bodygroups)) then
|
||||
entity:SetBodyGroups(bodygroups)
|
||||
end
|
||||
|
||||
local sequence = entity:LookupSequence("idle_unarmed")
|
||||
|
||||
if (sequence <= 0) then
|
||||
sequence = entity:SelectWeightedSequence(ACT_IDLE)
|
||||
end
|
||||
|
||||
if (sequence > 0) then
|
||||
entity:ResetSequence(sequence)
|
||||
else
|
||||
local found = false
|
||||
|
||||
for _, v in ipairs(entity:GetSequenceList()) do
|
||||
if ((v:lower():find("idle") or v:lower():find("fly")) and v != "idlenoise") then
|
||||
entity:ResetSequence(v)
|
||||
found = true
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if (!found) then
|
||||
entity:ResetSequence(4)
|
||||
end
|
||||
end
|
||||
|
||||
self.Entity = entity
|
||||
end
|
||||
|
||||
function PANEL:LayoutEntity()
|
||||
local scrW, scrH = ScrW(), ScrH()
|
||||
local xRatio = gui.MouseX() / scrW
|
||||
local yRatio = gui.MouseY() / scrH
|
||||
local x, _ = self:LocalToScreen(self:GetWide() / 2)
|
||||
local xRatio2 = x / scrW
|
||||
local entity = self.Entity
|
||||
|
||||
entity:SetPoseParameter("head_pitch", yRatio*90 - 30)
|
||||
entity:SetPoseParameter("head_yaw", (xRatio - xRatio2)*90 - 5)
|
||||
entity:SetAngles(MODEL_ANGLE)
|
||||
entity:SetIK(false)
|
||||
|
||||
if (self.copyLocalSequence) then
|
||||
entity:SetSequence(LocalPlayer():GetSequence())
|
||||
entity:SetPoseParameter("move_yaw", 360 * LocalPlayer():GetPoseParameter("move_yaw") - 180)
|
||||
end
|
||||
|
||||
self:RunAnimation()
|
||||
end
|
||||
|
||||
function PANEL:DrawModel()
|
||||
local brightness = self.brightness * 0.4
|
||||
local brightness2 = self.brightness * 1.5
|
||||
|
||||
render.SetStencilEnable(false)
|
||||
render.SetColorMaterial()
|
||||
render.SetColorModulation(1, 1, 1)
|
||||
render.SetModelLighting(0, brightness2, brightness2, brightness2)
|
||||
|
||||
for i = 1, 4 do
|
||||
render.SetModelLighting(i, brightness, brightness, brightness)
|
||||
end
|
||||
|
||||
local fraction = (brightness / 1) * 0.1
|
||||
|
||||
render.SetModelLighting(5, fraction, fraction, fraction)
|
||||
|
||||
-- Excecute Some stuffs
|
||||
if (self.enableHook) then
|
||||
hook.Run("DrawHelixModelView", self, self.Entity)
|
||||
end
|
||||
|
||||
self.Entity:DrawModel()
|
||||
|
||||
if (self.enableHook) then
|
||||
hook.Run("PostDrawHelixModelView", self, self.Entity)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed()
|
||||
end
|
||||
|
||||
vgui.Register("ixModelPanel", PANEL, "DModelPanel")
|
||||
280
gamemodes/helix/gamemode/core/derma/cl_notice.lua
Normal file
280
gamemodes/helix/gamemode/core/derma/cl_notice.lua
Normal file
@@ -0,0 +1,280 @@
|
||||
--[[
|
||||
| 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 animationTime = 0.75
|
||||
|
||||
-- notice manager
|
||||
-- this manages positions/animations for notice panels
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSize(ScrW() * 0.4, ScrH())
|
||||
self:SetPos(ScrW() - ScrW() * 0.4, 0)
|
||||
self:SetZPos(-99999)
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
|
||||
self.notices = {}
|
||||
self.padding = 4
|
||||
end
|
||||
|
||||
function PANEL:GetAll()
|
||||
return self.notices
|
||||
end
|
||||
|
||||
function PANEL:Clear()
|
||||
for _, v in ipairs(self.notices) do
|
||||
self:RemoveNotice(v)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:AddNotice(text, bError)
|
||||
if (IsValid(ix.gui.characterMenu) and !ix.gui.characterMenu.bClosing) then
|
||||
return
|
||||
end
|
||||
|
||||
local textLength = text:utf8len()
|
||||
|
||||
local panel = self:Add("ixNotice")
|
||||
panel:SetText(text)
|
||||
panel:SetError(bError or text:utf8sub(textLength, textLength) == "!")
|
||||
panel:SizeToContents()
|
||||
panel.currentY = -panel:GetTall()
|
||||
panel:SetPos(self.padding, panel.currentY)
|
||||
|
||||
-- setup duration timer
|
||||
panel:CreateAnimation(ix.option.Get("noticeDuration", 8), {
|
||||
index = 2,
|
||||
target = {duration = 1},
|
||||
bIgnoreConfig = true,
|
||||
|
||||
OnComplete = function(animation, this)
|
||||
self:RemoveNotice(this)
|
||||
end
|
||||
})
|
||||
|
||||
table.insert(self.notices, 1, panel)
|
||||
self:Organize()
|
||||
|
||||
-- remove old notice if we've hit the limit of notices
|
||||
if (#self.notices > ix.option.Get("noticeMax", 4)) then
|
||||
for i = #self.notices, 1, -1 do
|
||||
local notice = self.notices[i]
|
||||
|
||||
if (IsValid(notice) and !notice.bClosing) then
|
||||
self:RemoveNotice(notice)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
function PANEL:RemoveNotice(panel)
|
||||
panel.bClosing = true
|
||||
panel:CreateAnimation(animationTime, {
|
||||
index = 3,
|
||||
target = {outAnimation = 0},
|
||||
easing = "outQuint",
|
||||
|
||||
OnComplete = function(animation, this)
|
||||
local toRemove
|
||||
|
||||
for k, v in ipairs(self.notices) do
|
||||
if (v == this) then
|
||||
toRemove = k
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if (toRemove) then
|
||||
table.remove(self.notices, toRemove)
|
||||
end
|
||||
|
||||
this:SetText("") -- (hack) text remains for a frame after remove is called, so let's make sure we don't draw it
|
||||
this:Remove()
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
-- update target Y positions and animations
|
||||
function PANEL:Organize()
|
||||
local currentTarget = self.padding
|
||||
|
||||
for _, v in ipairs(self.notices) do
|
||||
v:CreateAnimation(animationTime, {
|
||||
index = 1,
|
||||
target = {currentY = currentTarget},
|
||||
easing = "outElastic",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetPos(
|
||||
self:GetWide() - panel:GetWide() - self.padding,
|
||||
math.min(panel.currentY + 1, currentTarget) -- easing eventually hits subpixel movement so we level it off
|
||||
)
|
||||
end
|
||||
})
|
||||
|
||||
currentTarget = currentTarget + self.padding + v:GetTall()
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixNoticeManager", PANEL, "Panel")
|
||||
|
||||
-- notice panel
|
||||
-- these do not manage their own enter/exit animations or lifetime
|
||||
DEFINE_BASECLASS("DLabel")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "bError", "Error", FORCE_BOOL)
|
||||
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSize(256, 36)
|
||||
self:SetContentAlignment(5)
|
||||
self:SetExpensiveShadow(1, Color(0, 0, 0, 150))
|
||||
self:SetFont("ixNoticeFont")
|
||||
self:SetTextColor(color_white)
|
||||
self:SetDrawOnTop(true)
|
||||
self:DockPadding(0, 0, 0, 0)
|
||||
self:DockMargin(0, 0, 0, 0)
|
||||
|
||||
self.bError = false
|
||||
self.bHovered = false
|
||||
|
||||
self.errorAnimation = 0
|
||||
self.padding = 8
|
||||
self.currentY = 0
|
||||
self.duration = 0
|
||||
self.outAnimation = 1
|
||||
self.alpha = 255
|
||||
|
||||
LocalPlayer():EmitSound("Helix.Notify")
|
||||
end
|
||||
|
||||
function PANEL:SetError(bValue)
|
||||
self.bError = tobool(bValue)
|
||||
|
||||
if (bValue) then
|
||||
self.errorAnimation = 1
|
||||
self:CreateAnimation(animationTime, {
|
||||
index = 5,
|
||||
target = {errorAnimation = 0},
|
||||
easing = "outQuint"
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
local contentWidth, contentHeight = self:GetContentSize()
|
||||
contentWidth = contentWidth + self.padding * 2
|
||||
contentHeight = contentHeight + self.padding * 2
|
||||
|
||||
local manager = ix.gui.notices
|
||||
local maxWidth = math.min(IsValid(manager) and (manager:GetWide() - manager:GetPadding() * 2) or ScrW(), contentWidth)
|
||||
|
||||
if (contentWidth > maxWidth) then
|
||||
self:SetWide(maxWidth)
|
||||
self:SetTextInset(self.padding * 2, 0)
|
||||
self:SetWrap(true)
|
||||
|
||||
self:SizeToContentsY()
|
||||
self:SetWide(self:GetContentSize())
|
||||
else
|
||||
self:SetSize(contentWidth, contentHeight)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SizeToContentsY()
|
||||
BaseClass.SizeToContentsY(self)
|
||||
self:SetTall(self:GetTall() + self.padding * 2)
|
||||
end
|
||||
|
||||
function PANEL:OnMouseHover()
|
||||
self:CreateAnimation(animationTime * 0.5, {
|
||||
index = 4,
|
||||
target = {alpha = 0},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.alpha)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:OnMouseLeave()
|
||||
self:CreateAnimation(animationTime * 0.5, {
|
||||
index = 4,
|
||||
target = {alpha = 255},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.alpha)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
if (self.outAnimation < 1) then
|
||||
local x, y = self:LocalToScreen(0, 0)
|
||||
render.SetScissorRect(x, y, x + self:GetWide(), y + (self:GetTall() * self.outAnimation), true)
|
||||
end
|
||||
|
||||
local x, y = self:LocalToScreen(0, 0)
|
||||
local mouseX, mouseY = gui.MousePos()
|
||||
|
||||
if (mouseX >= x and mouseX <= x + width and
|
||||
mouseY >= y and mouseY <= y + height) then
|
||||
if (!self.bHovered) then
|
||||
self.bHovered = true
|
||||
self:OnMouseHover()
|
||||
end
|
||||
elseif (self.bHovered) then
|
||||
self.bHovered = false
|
||||
self:OnMouseLeave()
|
||||
end
|
||||
|
||||
ix.util.DrawBlur(self)
|
||||
|
||||
if (self.errorAnimation > 0) then
|
||||
local color = derma.GetColor("Error", self)
|
||||
|
||||
surface.SetDrawColor(
|
||||
color.r * self.errorAnimation,
|
||||
color.g * self.errorAnimation,
|
||||
color.b * self.errorAnimation,
|
||||
self.errorAnimation * 255 + ((1 - self.errorAnimation) * 66)
|
||||
)
|
||||
else
|
||||
surface.SetDrawColor(0, 0, 0, 66)
|
||||
end
|
||||
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
|
||||
surface.SetDrawColor(self.bError and derma.GetColor("Error", self) or ix.config.Get("color"))
|
||||
surface.DrawRect(0, height - 1, width * self.duration, 1)
|
||||
end
|
||||
|
||||
function PANEL:PaintOver(width, height)
|
||||
render.SetScissorRect(0, 0, 0, 0, false)
|
||||
end
|
||||
|
||||
vgui.Register("ixNotice", PANEL, "DLabel")
|
||||
|
||||
if (IsValid(ix.gui.notices)) then
|
||||
ix.gui.notices:Remove()
|
||||
ix.gui.notices = vgui.Create("ixNoticeManager")
|
||||
else
|
||||
ix.gui.notices = vgui.Create("ixNoticeManager")
|
||||
end
|
||||
98
gamemodes/helix/gamemode/core/derma/cl_noticebar.lua
Normal file
98
gamemodes/helix/gamemode/core/derma/cl_noticebar.lua
Normal file
@@ -0,0 +1,98 @@
|
||||
--[[
|
||||
| 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 = {
|
||||
types = {
|
||||
"Info", -- info
|
||||
"Success", -- success
|
||||
"Error" -- error
|
||||
}
|
||||
}
|
||||
|
||||
AccessorFunc(PANEL, "type", "Type", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "length", "Length", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "hidden", "Hidden", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
self.type = 1
|
||||
self.padding = 8
|
||||
self.length = 4
|
||||
self.currentY = 0
|
||||
self.hidden = true
|
||||
|
||||
self.text = self:Add("DLabel")
|
||||
self.text:SetFont("ixNoticeFont")
|
||||
self.text:SetContentAlignment(5)
|
||||
self.text:SetTextColor(color_white)
|
||||
self.text:SizeToContents()
|
||||
self.text:Dock(FILL)
|
||||
|
||||
self:SetSize(self:GetParent():GetWide() - (self.padding * 4), self.text:GetTall() + (self.padding * 2))
|
||||
self:SetPos(self.padding * 2, -self:GetTall() - self.padding)
|
||||
end
|
||||
|
||||
function PANEL:SetFont(value)
|
||||
self.text:SetFont(value)
|
||||
self.text:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:SetText(text)
|
||||
self.text:SetText(text)
|
||||
self.text:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:Slide(direction, length)
|
||||
direction = direction or "up"
|
||||
length = length or 0.5
|
||||
|
||||
timer.Remove("ixNoticeBarAnimation")
|
||||
|
||||
local x, _ = self:GetPos()
|
||||
local baseY = direction == "up" and self.padding * 2 or (-self:GetTall() - self.padding)
|
||||
local targetY = direction == "up" and (-self:GetTall() - self.padding) or self.padding * 2
|
||||
local easing = direction == "up" and "outQuint" or "outElastic"
|
||||
|
||||
self:SetPos(x, baseY)
|
||||
self.currentY = baseY
|
||||
self.hidden = direction == "up"
|
||||
|
||||
self:CreateAnimation(length, {
|
||||
target = {currentY = targetY},
|
||||
easing = easing,
|
||||
|
||||
Think = function(animation, panel)
|
||||
local lastX, _ = panel:GetPos()
|
||||
panel:SetPos(lastX, panel.currentY)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
function PANEL:Show(bRemove)
|
||||
self:Slide("down")
|
||||
|
||||
timer.Create("ixNoticeBarAnimation", self.length - 0.5, 1, function()
|
||||
if (!IsValid(self)) then
|
||||
return
|
||||
end
|
||||
|
||||
self:Slide("up")
|
||||
end)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
local color = derma.GetColor(self.types[self.type], self)
|
||||
|
||||
surface.SetDrawColor(color)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixNoticeBar", PANEL, "Panel")
|
||||
253
gamemodes/helix/gamemode/core/derma/cl_overrides.lua
Normal file
253
gamemodes/helix/gamemode/core/derma/cl_overrides.lua
Normal file
@@ -0,0 +1,253 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- overrides standard derma panels to add/change functionality
|
||||
|
||||
local PANEL = {}
|
||||
local OVERRIDES = {}
|
||||
|
||||
-- @todo remove me when autorefresh support is no longer needed
|
||||
local function OverridePanel(name, func)
|
||||
PANEL = vgui.GetControlTable(name)
|
||||
|
||||
if (!istable(PANEL)) then
|
||||
return
|
||||
end
|
||||
|
||||
OVERRIDES = {}
|
||||
func()
|
||||
|
||||
for k, _ in pairs(PANEL) do
|
||||
local overrideName = "ix" .. k
|
||||
|
||||
if (PANEL[overrideName] and !OVERRIDES[k]) then
|
||||
print("unhooking override ", overrideName)
|
||||
|
||||
PANEL[k] = PANEL[overrideName]
|
||||
PANEL[overrideName] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Override(name)
|
||||
local oldMethod = "ix" .. name
|
||||
OVERRIDES[name] = true
|
||||
|
||||
if (PANEL[oldMethod]) then
|
||||
return
|
||||
end
|
||||
|
||||
PANEL[oldMethod] = PANEL[name]
|
||||
end
|
||||
|
||||
OverridePanel("DMenuOption", function()
|
||||
function PANEL:PerformLayout()
|
||||
self:SizeToContents()
|
||||
self:SetWide(self:GetWide() + 30)
|
||||
|
||||
local w = math.max(self:GetParent():GetWide(), self:GetWide())
|
||||
|
||||
self:SetSize(w, self:GetTall() + 4)
|
||||
|
||||
if (self.SubMenuArrow) then
|
||||
self.SubMenuArrow:SetSize(15, 15)
|
||||
self.SubMenuArrow:CenterVertical()
|
||||
self.SubMenuArrow:AlignRight(4)
|
||||
end
|
||||
|
||||
DButton.PerformLayout(self)
|
||||
end
|
||||
end)
|
||||
|
||||
OverridePanel("DMenu", function()
|
||||
local animationTime = 0.33
|
||||
|
||||
Override("Init")
|
||||
function PANEL:Init(...)
|
||||
self:ixInit(...)
|
||||
|
||||
self.ixAnimation = 0
|
||||
end
|
||||
|
||||
function PANEL:SetFont(font)
|
||||
for _, v in pairs(self:GetCanvas():GetChildren()) do
|
||||
v:SetFont(font)
|
||||
v:SizeToContents()
|
||||
end
|
||||
|
||||
-- reposition for the new font
|
||||
self:InvalidateLayout(true)
|
||||
self:Open(self.ixX, self.ixY, false, self.ixOwnerPanel)
|
||||
end
|
||||
|
||||
Override("SetSize")
|
||||
function PANEL:SetSize(width, height)
|
||||
self:ixSetSize(width, height)
|
||||
self.ixTargetHeight = height
|
||||
end
|
||||
|
||||
Override("PerformLayout")
|
||||
function PANEL:PerformLayout(...)
|
||||
self:ixPerformLayout(...)
|
||||
|
||||
if (self.ixAnimating) then
|
||||
self.VBar:SetAlpha(0) -- setvisible doesn't seem to work here
|
||||
self:SetTall(self.ixAnimation * self.ixTargetHeight)
|
||||
else
|
||||
self.VBar:SetAlpha(255)
|
||||
end
|
||||
end
|
||||
|
||||
Override("OnMouseWheeled")
|
||||
function PANEL:OnMouseWheeled(delta)
|
||||
self:ixOnMouseWheeled(delta)
|
||||
|
||||
-- don't allow the input event to fall through
|
||||
return true
|
||||
end
|
||||
|
||||
Override("AddOption")
|
||||
function PANEL:AddOption(...)
|
||||
local panel = self:ixAddOption(...)
|
||||
|
||||
panel:SetTextColor(derma.GetColor("MenuLabel", self, color_black))
|
||||
panel:SetTextInset(6, 0) -- there is no icon functionality in DComboBoxes
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
Override("AddSubMenu")
|
||||
function PANEL:AddSubMenu(...)
|
||||
local menu, panel = self:ixAddSubMenu(...)
|
||||
|
||||
panel:SetTextColor(derma.GetColor("MenuLabel", self, color_black))
|
||||
panel:SetTextInset(6, 0) -- there is no icon functionality in DComboBoxes
|
||||
|
||||
return menu, panel
|
||||
end
|
||||
|
||||
Override("Open")
|
||||
function PANEL:Open(x, y, bSkipAnimation, ownerPanel)
|
||||
self.ixX, self.ixY, self.ixOwnerPanel = x, y, ownerPanel
|
||||
self:ixOpen(x, y, bSkipAnimation, ownerPanel)
|
||||
|
||||
if (ix.option.Get("disableAnimations")) then
|
||||
return
|
||||
end
|
||||
|
||||
-- remove pac3 derma menu hooks since animations don't play nicely
|
||||
hook.Remove("CloseDermaMenus", self)
|
||||
hook.Remove("Think", self)
|
||||
|
||||
self.ixAnimating = true
|
||||
self:CreateAnimation(animationTime, {
|
||||
index = 1,
|
||||
target = {ixAnimation = 1},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:InvalidateLayout(true)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
panel.ixAnimating = nil
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
Override("Hide")
|
||||
function PANEL:Hide()
|
||||
if (ix.option.Get("disableAnimations")) then
|
||||
self:ixHide()
|
||||
return
|
||||
end
|
||||
|
||||
self.ixAnimating = true
|
||||
self:SetVisible(true)
|
||||
self:CreateAnimation(animationTime * 0.5, {
|
||||
index = 1,
|
||||
target = {ixAnimation = 0},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:InvalidateLayout(true)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
panel.ixAnimating = false
|
||||
panel:ixHide()
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
Override("Remove")
|
||||
function PANEL:Remove()
|
||||
if (self.ixRemoving) then
|
||||
return
|
||||
end
|
||||
|
||||
if (ix.option.Get("disableAnimations")) then
|
||||
self:ixRemove()
|
||||
return
|
||||
end
|
||||
|
||||
self.ixAnimating = true
|
||||
self.ixRemoving = true
|
||||
self:SetVisible(true)
|
||||
|
||||
self:CreateAnimation(animationTime * 0.5, {
|
||||
index = 1,
|
||||
target = {ixAnimation = 0},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:InvalidateLayout(true)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
panel:ixRemove()
|
||||
end
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
||||
OverridePanel("DComboBox", function()
|
||||
Override("OpenMenu")
|
||||
function PANEL:OpenMenu()
|
||||
self:ixOpenMenu()
|
||||
|
||||
if (IsValid(self.Menu)) then
|
||||
local _, y = self.Menu:LocalToScreen(self.Menu:GetPos())
|
||||
|
||||
self.Menu:SetFont(self:GetFont())
|
||||
self.Menu:SetMaxHeight(ScrH() - y)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
OverridePanel("DScrollPanel", function()
|
||||
Override("ScrollToChild")
|
||||
function PANEL:ScrollToChild(panel)
|
||||
-- docked panels required InvalidateParent in order to retrieve their position correctly
|
||||
if (panel:GetDock() != NODOCK) then
|
||||
panel:InvalidateParent(true)
|
||||
else
|
||||
self:PerformLayout()
|
||||
end
|
||||
|
||||
local _, y = self.pnlCanvas:GetChildPosition(panel)
|
||||
|
||||
y = y + panel:GetTall() * 0.5
|
||||
y = y - self:GetTall() * 0.5
|
||||
|
||||
self.VBar:SetScroll(y)
|
||||
end
|
||||
end)
|
||||
359
gamemodes/helix/gamemode/core/derma/cl_scoreboard.lua
Normal file
359
gamemodes/helix/gamemode/core/derma/cl_scoreboard.lua
Normal file
@@ -0,0 +1,359 @@
|
||||
--[[
|
||||
| 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 rowPaintFunctions = {
|
||||
function(width, height)
|
||||
end,
|
||||
|
||||
function(width, height)
|
||||
surface.SetDrawColor(30, 30, 30, 25)
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
}
|
||||
|
||||
-- character icon
|
||||
-- we can't customize the rendering of ModelImage so we have to do it ourselves
|
||||
local PANEL = {}
|
||||
local BODYGROUPS_EMPTY = "000000000"
|
||||
|
||||
AccessorFunc(PANEL, "model", "Model", FORCE_STRING)
|
||||
AccessorFunc(PANEL, "bHidden", "Hidden", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSize(64, 64)
|
||||
self.bodygroups = BODYGROUPS_EMPTY
|
||||
end
|
||||
|
||||
function PANEL:SetModel(model, skin, bodygroups)
|
||||
model = model:gsub("\\", "/")
|
||||
|
||||
if (isstring(bodygroups)) then
|
||||
if (bodygroups:len() == 9) then
|
||||
for i = 1, bodygroups:len() do
|
||||
self:SetBodygroup(i, tonumber(bodygroups[i]) or 0)
|
||||
end
|
||||
else
|
||||
self.bodygroups = BODYGROUPS_EMPTY
|
||||
end
|
||||
end
|
||||
|
||||
self.model = model
|
||||
self.skin = skin
|
||||
self.path = "materials/spawnicons/" ..
|
||||
model:sub(1, #model - 4) .. -- remove extension
|
||||
((isnumber(skin) and skin > 0) and ("_skin" .. tostring(skin)) or "") .. -- skin number
|
||||
(self.bodygroups != BODYGROUPS_EMPTY and ("_" .. self.bodygroups) or "") .. -- bodygroups
|
||||
".png"
|
||||
|
||||
local material = Material(self.path, "smooth")
|
||||
|
||||
-- we don't have a cached spawnicon texture, so we need to forcefully generate one
|
||||
if (material:IsError()) then
|
||||
self.id = "ixScoreboardIcon" .. self.path
|
||||
self.renderer = self:Add("ModelImage")
|
||||
self.renderer:SetVisible(false)
|
||||
self.renderer:SetModel(model, skin, self.bodygroups)
|
||||
self.renderer:RebuildSpawnIcon()
|
||||
|
||||
-- this is the only way to get a callback for generated spawn icons, it's bad but it's only done once
|
||||
hook.Add("SpawniconGenerated", self.id, function(lastModel, filePath, modelsLeft)
|
||||
filePath = filePath:gsub("\\", "/"):lower()
|
||||
|
||||
if (filePath == self.path) then
|
||||
hook.Remove("SpawniconGenerated", self.id)
|
||||
|
||||
self.material = Material(filePath, "smooth")
|
||||
self.renderer:Remove()
|
||||
end
|
||||
end)
|
||||
else
|
||||
self.material = material
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetBodygroup(k, v)
|
||||
if (k < 0 or k > 8 or v < 0 or v > 9) then
|
||||
return
|
||||
end
|
||||
|
||||
self.bodygroups = self.bodygroups:SetChar(k + 1, v)
|
||||
end
|
||||
|
||||
function PANEL:GetModel()
|
||||
return self.model or "models/error.mdl"
|
||||
end
|
||||
|
||||
function PANEL:GetSkin()
|
||||
return self.skin or 1
|
||||
end
|
||||
|
||||
function PANEL:DoClick()
|
||||
end
|
||||
|
||||
function PANEL:DoRightClick()
|
||||
end
|
||||
|
||||
function PANEL:OnMouseReleased(key)
|
||||
if (key == MOUSE_LEFT) then
|
||||
self:DoClick()
|
||||
elseif (key == MOUSE_RIGHT) then
|
||||
self:DoRightClick()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
if (!self.material) then
|
||||
return
|
||||
end
|
||||
|
||||
surface.SetMaterial(self.material)
|
||||
surface.SetDrawColor(self.bHidden and color_black or color_white)
|
||||
surface.DrawTexturedRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
function PANEL:Remove()
|
||||
if (self.id) then
|
||||
hook.Remove("SpawniconGenerated", self.id)
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixScoreboardIcon", PANEL, "Panel")
|
||||
|
||||
-- player row
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "paintFunction", "BackgroundPaintFunction")
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetTall(64)
|
||||
|
||||
self.icon = self:Add("ixScoreboardIcon")
|
||||
self.icon:Dock(LEFT)
|
||||
self.icon.DoRightClick = function()
|
||||
local client = self.player
|
||||
|
||||
if (!IsValid(client)) then
|
||||
return
|
||||
end
|
||||
|
||||
local menu = DermaMenu()
|
||||
|
||||
menu:AddOption(L("viewProfile"), function()
|
||||
client:ShowProfile()
|
||||
end)
|
||||
|
||||
menu:AddOption(L("copySteamID"), function()
|
||||
SetClipboardText(client:IsBot() and client:EntIndex() or client:SteamID())
|
||||
end)
|
||||
|
||||
hook.Run("PopulateScoreboardPlayerMenu", client, menu)
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
self.icon:SetHelixTooltip(function(tooltip)
|
||||
local client = self.player
|
||||
|
||||
if (IsValid(self) and IsValid(client)) then
|
||||
ix.hud.PopulatePlayerTooltip(tooltip, client)
|
||||
end
|
||||
end)
|
||||
|
||||
self.name = self:Add("DLabel")
|
||||
self.name:DockMargin(4, 4, 0, 0)
|
||||
self.name:Dock(TOP)
|
||||
self.name:SetTextColor(color_white)
|
||||
self.name:SetFont("ixGenericFont")
|
||||
|
||||
self.description = self:Add("DLabel")
|
||||
self.description:DockMargin(5, 0, 0, 0)
|
||||
self.description:Dock(TOP)
|
||||
self.description:SetTextColor(color_white)
|
||||
self.description:SetFont("ixSmallFont")
|
||||
|
||||
self.paintFunction = rowPaintFunctions[1]
|
||||
self.nextThink = CurTime() + 1
|
||||
end
|
||||
|
||||
function PANEL:Update()
|
||||
local client = self.player
|
||||
local model = client:GetModel()
|
||||
local skin = client:GetSkin()
|
||||
local name = client:GetName()
|
||||
local description = hook.Run("GetCharacterDescription", client) or
|
||||
(client:GetCharacter() and client:GetCharacter():GetDescription()) or ""
|
||||
|
||||
local bRecognize = false
|
||||
local localCharacter = LocalPlayer():GetCharacter()
|
||||
local character = IsValid(self.player) and self.player:GetCharacter()
|
||||
|
||||
if (localCharacter and character) then
|
||||
bRecognize = hook.Run("IsCharacterRecognized", localCharacter, character:GetID())
|
||||
or hook.Run("IsPlayerRecognized", self.player)
|
||||
end
|
||||
|
||||
self.icon:SetHidden(!bRecognize)
|
||||
self:SetZPos(bRecognize and 1 or 2)
|
||||
|
||||
-- no easy way to check bodygroups so we'll just set them anyway
|
||||
for _, v in pairs(client:GetBodyGroups()) do
|
||||
self.icon:SetBodygroup(v.id, client:GetBodygroup(v.id))
|
||||
end
|
||||
|
||||
if (self.icon:GetModel() != model or self.icon:GetSkin() != skin) then
|
||||
self.icon:SetModel(model, skin)
|
||||
self.icon:SetTooltip(nil)
|
||||
end
|
||||
|
||||
if (self.name:GetText() != name) then
|
||||
self.name:SetText(name)
|
||||
self.name:SizeToContents()
|
||||
end
|
||||
|
||||
if (self.description:GetText() != description) then
|
||||
self.description:SetText(description)
|
||||
self.description:SizeToContents()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
if (CurTime() >= self.nextThink) then
|
||||
local client = self.player
|
||||
|
||||
if (!IsValid(client) or !client:GetCharacter() or self.character != client:GetCharacter() or self.team != client:Team()) then
|
||||
self:Remove()
|
||||
self:GetParent():SizeToContents()
|
||||
end
|
||||
|
||||
self.nextThink = CurTime() + 1
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetPlayer(client)
|
||||
self.player = client
|
||||
self.team = client:Team()
|
||||
self.character = client:GetCharacter()
|
||||
|
||||
self:Update()
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
self.paintFunction(width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixScoreboardRow", PANEL, "EditablePanel")
|
||||
|
||||
-- faction grouping
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "faction", "Faction")
|
||||
|
||||
function PANEL:Init()
|
||||
self:DockMargin(0, 0, 0, 16)
|
||||
self:SetTall(32)
|
||||
|
||||
self.nextThink = 0
|
||||
end
|
||||
|
||||
function PANEL:AddPlayer(client, index)
|
||||
if (!IsValid(client) or !client:GetCharacter() or hook.Run("ShouldShowPlayerOnScoreboard", client) == false) then
|
||||
return false
|
||||
end
|
||||
|
||||
local id = index % 2 == 0 and 1 or 2
|
||||
local panel = self:Add("ixScoreboardRow")
|
||||
panel:SetPlayer(client)
|
||||
panel:Dock(TOP)
|
||||
panel:SetZPos(2)
|
||||
panel:SetBackgroundPaintFunction(rowPaintFunctions[id])
|
||||
|
||||
self:SizeToContents()
|
||||
client.ixScoreboardSlot = panel
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function PANEL:SetFaction(faction)
|
||||
self:SetColor(faction.color)
|
||||
self:SetText(L(faction.name))
|
||||
|
||||
self.faction = faction
|
||||
end
|
||||
|
||||
function PANEL:Update()
|
||||
local faction = self.faction
|
||||
|
||||
if (team.NumPlayers(faction.index) == 0) then
|
||||
self:SetVisible(false)
|
||||
self:GetParent():InvalidateLayout()
|
||||
else
|
||||
local bHasPlayers
|
||||
|
||||
for k, v in ipairs(team.GetPlayers(faction.index)) do
|
||||
if (!IsValid(v.ixScoreboardSlot)) then
|
||||
if (self:AddPlayer(v, k)) then
|
||||
bHasPlayers = true
|
||||
end
|
||||
else
|
||||
v.ixScoreboardSlot:Update()
|
||||
bHasPlayers = true
|
||||
end
|
||||
end
|
||||
|
||||
self:SetVisible(bHasPlayers)
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixScoreboardFaction", PANEL, "ixCategoryPanel")
|
||||
|
||||
-- main scoreboard panel
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
if (IsValid(ix.gui.scoreboard)) then
|
||||
ix.gui.scoreboard:Remove()
|
||||
end
|
||||
|
||||
self:Dock(FILL)
|
||||
|
||||
self.factions = {}
|
||||
self.nextThink = 0
|
||||
|
||||
for i = 1, #ix.faction.indices do
|
||||
local faction = ix.faction.indices[i]
|
||||
|
||||
local panel = self:Add("ixScoreboardFaction")
|
||||
panel:SetFaction(faction)
|
||||
panel:Dock(TOP)
|
||||
|
||||
self.factions[i] = panel
|
||||
end
|
||||
|
||||
ix.gui.scoreboard = self
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
if (CurTime() >= self.nextThink) then
|
||||
for i = 1, #self.factions do
|
||||
local factionPanel = self.factions[i]
|
||||
|
||||
factionPanel:Update()
|
||||
end
|
||||
|
||||
self.nextThink = CurTime() + 0.5
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixScoreboard", PANEL, "DScrollPanel")
|
||||
|
||||
hook.Add("CreateMenuButtons", "ixScoreboard", function(tabs)
|
||||
tabs["scoreboard"] = function(container)
|
||||
container:Add("ixScoreboard")
|
||||
end
|
||||
end)
|
||||
781
gamemodes/helix/gamemode/core/derma/cl_settings.lua
Normal file
781
gamemodes/helix/gamemode/core/derma/cl_settings.lua
Normal file
@@ -0,0 +1,781 @@
|
||||
--[[
|
||||
| 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 panelMap = {
|
||||
[ix.type.bool] = "ixSettingsRowBool",
|
||||
[ix.type.array] = "ixSettingsRowArray",
|
||||
[ix.type.string] = "ixSettingsRowString",
|
||||
[ix.type.number] = "ixSettingsRowNumber",
|
||||
[ix.type.color] = "ixSettingsRowColor"
|
||||
}
|
||||
|
||||
local function EmitChange(pitch)
|
||||
LocalPlayer():EmitSound("weapons/ar2/ar2_empty.wav", 75, pitch or 150, 0.25)
|
||||
end
|
||||
|
||||
-- color setting
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self.color = table.Copy(color_white)
|
||||
self.padding = 4
|
||||
|
||||
self.panel = self:Add("Panel")
|
||||
self.panel:SetCursor("hand")
|
||||
self.panel:SetMouseInputEnabled(true)
|
||||
self.panel:Dock(RIGHT)
|
||||
self.panel.Paint = function(panel, width, height)
|
||||
local padding = self.padding
|
||||
|
||||
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
|
||||
surface.SetDrawColor(self.color)
|
||||
surface.DrawRect(padding, padding, width - padding * 2, height - padding * 2)
|
||||
end
|
||||
|
||||
self.panel.OnMousePressed = function(panel, key)
|
||||
if (key == MOUSE_LEFT) then
|
||||
self:OpenPicker()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OpenPicker()
|
||||
if (IsValid(self.picker)) then
|
||||
self.picker:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
self.picker = vgui.Create("ixSettingsRowColorPicker")
|
||||
self.picker:Attach(self)
|
||||
self.picker:SetValue(self.color)
|
||||
|
||||
self.picker.OnValueChanged = function(panel)
|
||||
local newColor = panel:GetValue()
|
||||
|
||||
if (newColor != self.color) then
|
||||
self.color = newColor
|
||||
self:OnValueChanged(newColor)
|
||||
end
|
||||
end
|
||||
|
||||
self.picker.OnValueUpdated = function(panel)
|
||||
self.color = panel:GetValue()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetValue(value)
|
||||
self.color = Color(value.r or 255, value.g or 255, value.b or 255, value.a or 255)
|
||||
end
|
||||
|
||||
function PANEL:GetValue()
|
||||
return self.color
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout(width, height)
|
||||
surface.SetFont("ixMenuButtonFont")
|
||||
local totalWidth = surface.GetTextSize("999")
|
||||
|
||||
self.panel:SetSize(totalWidth + self.padding * 2, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixSettingsRowColor", PANEL, "ixSettingsRow")
|
||||
|
||||
-- color setting picker
|
||||
DEFINE_BASECLASS("Panel")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "bDeleteSelf", "DeleteSelf", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
self.m_bIsMenuComponent = true
|
||||
self.bDeleteSelf = true
|
||||
|
||||
self.realHeight = 200
|
||||
self.height = 200
|
||||
self:SetSize(250, 200)
|
||||
self:DockPadding(4, 4, 4, 4)
|
||||
|
||||
self.picker = self:Add("DColorMixer")
|
||||
self.picker:Dock(FILL)
|
||||
self.picker.ValueChanged = function()
|
||||
self:OnValueUpdated()
|
||||
end
|
||||
|
||||
self:MakePopup()
|
||||
RegisterDermaMenuForClose(self)
|
||||
end
|
||||
|
||||
function PANEL:SetValue(value)
|
||||
self.picker:SetColor(Color(value.r or 255, value.g or 255, value.b or 255, value.a or 255))
|
||||
end
|
||||
|
||||
function PANEL:GetValue()
|
||||
return self.picker:GetColor()
|
||||
end
|
||||
|
||||
function PANEL:Attach(panel)
|
||||
self.attached = panel
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
local panel = self.attached
|
||||
|
||||
if (IsValid(panel)) then
|
||||
local width, height = self:GetSize()
|
||||
local x, y = panel:LocalToScreen(0, 0)
|
||||
|
||||
self:SetPos(
|
||||
math.Clamp(x + panel:GetWide() - width, 0, ScrW() - width),
|
||||
math.Clamp(y + panel:GetTall(), 0, ScrH() - height)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
function PANEL:OnValueChanged()
|
||||
end
|
||||
|
||||
function PANEL:OnValueUpdated()
|
||||
end
|
||||
|
||||
function PANEL:Remove()
|
||||
if (self.bClosing) then
|
||||
return
|
||||
end
|
||||
|
||||
self:OnValueChanged()
|
||||
|
||||
-- @todo open/close animations
|
||||
self.bClosing = true
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
BaseClass.Remove(self)
|
||||
end
|
||||
|
||||
vgui.Register("ixSettingsRowColorPicker", PANEL, "EditablePanel")
|
||||
|
||||
-- number setting
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.setting = self:Add("ixNumSlider")
|
||||
self.setting.nextUpdate = 0
|
||||
self.setting:Dock(RIGHT)
|
||||
self.setting.OnValueChanged = function(panel)
|
||||
self:OnValueChanged(self:GetValue())
|
||||
end
|
||||
self.setting.OnValueUpdated = function(panel)
|
||||
local fraction = panel:GetFraction()
|
||||
|
||||
if (fraction == 0) then
|
||||
EmitChange(75)
|
||||
return
|
||||
elseif (fraction == 1) then
|
||||
EmitChange(120)
|
||||
return
|
||||
end
|
||||
|
||||
if (SysTime() > panel.nextUpdate) then
|
||||
EmitChange(85 + fraction * 15)
|
||||
panel.nextUpdate = SysTime() + 0.05
|
||||
end
|
||||
end
|
||||
|
||||
local panel = self.setting:GetLabel()
|
||||
panel:SetCursor("hand")
|
||||
panel:SetMouseInputEnabled(true)
|
||||
panel.OnMousePressed = function(_, key)
|
||||
if (key == MOUSE_LEFT) then
|
||||
self:OpenEntry()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OpenEntry()
|
||||
if (IsValid(self.entry)) then
|
||||
self.entry:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
self.entry = vgui.Create("ixSettingsRowNumberEntry")
|
||||
self.entry:Attach(self)
|
||||
self.entry:SetValue(self:GetValue(), true)
|
||||
self.entry.OnValueChanged = function(panel)
|
||||
local value = math.Round(panel:GetValue(), self:GetDecimals())
|
||||
|
||||
if (value != self:GetValue()) then
|
||||
self:SetValue(value, true)
|
||||
self:OnValueChanged(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetValue(value, bNoNotify)
|
||||
self.setting:SetValue(value, bNoNotify)
|
||||
end
|
||||
|
||||
function PANEL:GetValue()
|
||||
return self.setting:GetValue()
|
||||
end
|
||||
|
||||
function PANEL:SetMin(value)
|
||||
self.setting:SetMin(value)
|
||||
end
|
||||
|
||||
function PANEL:SetMax(value)
|
||||
self.setting:SetMax(value)
|
||||
end
|
||||
|
||||
function PANEL:SetDecimals(value)
|
||||
self.setting:SetDecimals(value)
|
||||
end
|
||||
|
||||
function PANEL:GetDecimals()
|
||||
return self.setting:GetDecimals()
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout(width, height)
|
||||
self.setting:SetWide(width * 0.5)
|
||||
end
|
||||
|
||||
vgui.Register("ixSettingsRowNumber", PANEL, "ixSettingsRow")
|
||||
|
||||
-- number setting entry
|
||||
DEFINE_BASECLASS("Panel")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "bDeleteSelf", "DeleteSelf", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
surface.SetFont("ixMenuButtonFont")
|
||||
local width, height = surface.GetTextSize("999999")
|
||||
|
||||
self.m_bIsMenuComponent = true
|
||||
self.bDeleteSelf = true
|
||||
|
||||
self.realHeight = 200
|
||||
self.height = 200
|
||||
self:SetSize(width, height)
|
||||
self:DockPadding(4, 4, 4, 4)
|
||||
|
||||
self.textEntry = self:Add("ixTextEntry")
|
||||
self.textEntry:SetNumeric(true)
|
||||
self.textEntry:SetFont("ixMenuButtonFont")
|
||||
self.textEntry:Dock(FILL)
|
||||
self.textEntry:RequestFocus()
|
||||
self.textEntry.OnEnter = function()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
self:MakePopup()
|
||||
RegisterDermaMenuForClose(self)
|
||||
end
|
||||
|
||||
function PANEL:SetValue(value, bInitial)
|
||||
value = tostring(value)
|
||||
self.textEntry:SetValue(value)
|
||||
|
||||
if (bInitial) then
|
||||
self.textEntry:SetCaretPos(value:utf8len())
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:GetValue()
|
||||
return tonumber(self.textEntry:GetValue()) or 0
|
||||
end
|
||||
|
||||
function PANEL:Attach(panel)
|
||||
self.attached = panel
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
local panel = self.attached
|
||||
|
||||
if (IsValid(panel)) then
|
||||
local width, height = self:GetSize()
|
||||
local x, y = panel:LocalToScreen(0, 0)
|
||||
|
||||
self:SetPos(
|
||||
math.Clamp(x + panel:GetWide() - width, 0, ScrW() - width),
|
||||
math.Clamp(y + panel:GetTall(), 0, ScrH() - height)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
surface.SetDrawColor(derma.GetColor("DarkerBackground", self))
|
||||
surface.DrawRect(0, 0, width, height)
|
||||
end
|
||||
|
||||
function PANEL:OnValueChanged()
|
||||
end
|
||||
|
||||
function PANEL:OnValueUpdated()
|
||||
end
|
||||
|
||||
function PANEL:Remove()
|
||||
if (self.bClosing) then
|
||||
return
|
||||
end
|
||||
|
||||
self:OnValueChanged()
|
||||
|
||||
-- @todo open/close animations
|
||||
self.bClosing = true
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
BaseClass.Remove(self)
|
||||
end
|
||||
|
||||
vgui.Register("ixSettingsRowNumberEntry", PANEL, "EditablePanel")
|
||||
|
||||
-- string setting
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.setting = self:Add("ixTextEntry")
|
||||
self.setting:Dock(RIGHT)
|
||||
self.setting:SetFont("ixMenuButtonFont")
|
||||
self.setting:SetBackgroundColor(derma.GetColor("DarkerBackground", self))
|
||||
self.setting.OnEnter = function()
|
||||
self:OnValueChanged(self:GetValue())
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetValue(value)
|
||||
self.setting:SetValue(tostring(value))
|
||||
end
|
||||
|
||||
function PANEL:GetValue()
|
||||
return self.setting:GetValue()
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout(width, height)
|
||||
self.setting:SetWide(width * 0.5)
|
||||
end
|
||||
|
||||
vgui.Register("ixSettingsRowString", PANEL, "ixSettingsRow")
|
||||
|
||||
-- bool setting
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.setting = self:Add("ixCheckBox")
|
||||
self.setting:Dock(RIGHT)
|
||||
self.setting.DoClick = function(panel)
|
||||
self:OnValueChanged(self:GetValue())
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetValue(bValue)
|
||||
bValue = tobool(bValue)
|
||||
|
||||
self.setting:SetChecked(bValue, true)
|
||||
end
|
||||
|
||||
function PANEL:GetValue()
|
||||
return self.setting:GetChecked()
|
||||
end
|
||||
|
||||
vgui.Register("ixSettingsRowBool", PANEL, "ixSettingsRow")
|
||||
|
||||
-- array setting
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.array = {}
|
||||
|
||||
self.setting = self:Add("DComboBox")
|
||||
self.setting:Dock(RIGHT)
|
||||
self.setting:SetFont("ixMenuButtonFont")
|
||||
self.setting:SetTextColor(color_white)
|
||||
self.setting.OnSelect = function(panel)
|
||||
self:OnValueChanged(self:GetValue())
|
||||
|
||||
panel:SizeToContents()
|
||||
panel:SetWide(panel:GetWide() + 12) -- padding for arrow (nice)
|
||||
|
||||
if (!self.bInitial) then
|
||||
EmitChange()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Populate(key, info)
|
||||
if (!isfunction(info.populate)) then
|
||||
ErrorNoHalt(string.format("expected populate function for array option '%s'", key))
|
||||
return
|
||||
end
|
||||
|
||||
local entries = info.populate()
|
||||
local i = 1
|
||||
|
||||
for k, v in pairs(entries) do
|
||||
self.setting:AddChoice(v, k)
|
||||
self.array[k] = i
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetValue(value)
|
||||
self.bInitial = true
|
||||
self.setting:ChooseOptionID(self.array[value])
|
||||
self.bInitial = false
|
||||
end
|
||||
|
||||
function PANEL:GetValue()
|
||||
return select(2, self.setting:GetSelected())
|
||||
end
|
||||
|
||||
vgui.Register("ixSettingsRowArray", PANEL, "ixSettingsRow")
|
||||
|
||||
-- settings row
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "backgroundIndex", "BackgroundIndex", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "bShowReset", "ShowReset", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
self:DockPadding(4, 4, 4, 4)
|
||||
|
||||
self.text = self:Add("DLabel")
|
||||
self.text:Dock(LEFT)
|
||||
self.text:SetFont("ixMenuButtonFont")
|
||||
self.text:SetExpensiveShadow(1, color_black)
|
||||
|
||||
self.backgroundIndex = 0
|
||||
end
|
||||
|
||||
function PANEL:SetShowReset(value, name, default)
|
||||
value = tobool(value)
|
||||
|
||||
if (value and !IsValid(self.reset)) then
|
||||
self.reset = self:Add("DButton")
|
||||
self.reset:SetFont("ixSmallTitleIcons")
|
||||
self.reset:SetText("x")
|
||||
self.reset:SetTextColor(ColorAlpha(derma.GetColor("Warning", self), 100))
|
||||
self.reset:Dock(LEFT)
|
||||
self.reset:DockMargin(4, 0, 0, 0)
|
||||
self.reset:SizeToContents()
|
||||
self.reset.Paint = nil
|
||||
self.reset.DoClick = function()
|
||||
self:OnResetClicked()
|
||||
end
|
||||
self.reset:SetHelixTooltip(function(tooltip)
|
||||
local title = tooltip:AddRow("title")
|
||||
title:SetImportant()
|
||||
title:SetText(L("resetDefault"))
|
||||
title:SetBackgroundColor(derma.GetColor("Warning", self))
|
||||
title:SizeToContents()
|
||||
|
||||
local description = tooltip:AddRow("description")
|
||||
description:SetText(L("resetDefaultDescription", tostring(name), tostring(default)))
|
||||
description:SizeToContents()
|
||||
end)
|
||||
elseif (!value and IsValid(self.reset)) then
|
||||
self.reset:Remove()
|
||||
end
|
||||
|
||||
self.bShowReset = value
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
if (IsValid(self.reset)) then
|
||||
self.reset:SetVisible(self:IsHovered() or self:IsOurChild(vgui.GetHoveredPanel()))
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnResetClicked()
|
||||
end
|
||||
|
||||
function PANEL:GetLabel()
|
||||
return self.text
|
||||
end
|
||||
|
||||
function PANEL:SetText(text)
|
||||
self.text:SetText(text)
|
||||
self:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:GetText()
|
||||
return self.text:GetText()
|
||||
end
|
||||
|
||||
-- implemented by row types
|
||||
function PANEL:GetValue()
|
||||
end
|
||||
|
||||
function PANEL:SetValue(value)
|
||||
end
|
||||
|
||||
-- meant for array types to populate combo box values
|
||||
function PANEL:Populate(key, info)
|
||||
end
|
||||
|
||||
-- called when value is changed by user
|
||||
function PANEL:OnValueChanged(newValue)
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
local _, top, _, bottom = self:GetDockPadding()
|
||||
|
||||
self.text:SizeToContents()
|
||||
self:SetTall(self.text:GetTall() + top + bottom)
|
||||
self.ixRealHeight = self:GetTall()
|
||||
self.ixHeight = self.ixRealHeight
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("PaintSettingsRowBackground", self, width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixSettingsRow", PANEL, "EditablePanel")
|
||||
|
||||
-- settings panel
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:Dock(FILL)
|
||||
self.rows = {}
|
||||
self.categories = {}
|
||||
|
||||
-- scroll panel
|
||||
DEFINE_BASECLASS("DScrollPanel")
|
||||
|
||||
self.canvas = self:Add("DScrollPanel")
|
||||
self.canvas:Dock(FILL)
|
||||
self.canvas.PerformLayout = function(panel)
|
||||
BaseClass.PerformLayout(panel)
|
||||
|
||||
if (!panel.VBar.Enabled) then
|
||||
panel.pnlCanvas:SetWide(panel:GetWide() - panel.VBar:GetWide())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:GetRowPanelName(type)
|
||||
return panelMap[type] or "ixSettingsRow"
|
||||
end
|
||||
|
||||
function PANEL:AddCategory(name)
|
||||
local panel = self.categories[name]
|
||||
|
||||
if (!IsValid(panel)) then
|
||||
panel = self.canvas:Add("ixCategoryPanel")
|
||||
panel:SetText(name)
|
||||
panel:Dock(TOP)
|
||||
panel:DockMargin(0, 8, 0, 0)
|
||||
|
||||
self.categories[name] = panel
|
||||
return panel
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:AddRow(type, category)
|
||||
category = self.categories[category]
|
||||
local id = panelMap[type]
|
||||
|
||||
if (!id) then
|
||||
ErrorNoHalt("attempted to create row with unimplemented type '" .. tostring(ix.type[type]) .. "'\n")
|
||||
id = "ixSettingsRow"
|
||||
end
|
||||
|
||||
local panel = (IsValid(category) and category or self.canvas):Add(id)
|
||||
panel:Dock(TOP)
|
||||
panel:SetBackgroundIndex(#self.rows % 2)
|
||||
|
||||
self.rows[#self.rows + 1] = panel
|
||||
return panel
|
||||
end
|
||||
|
||||
function PANEL:GetRows()
|
||||
return self.rows
|
||||
end
|
||||
|
||||
function PANEL:Clear()
|
||||
for _, v in ipairs(self.rows) do
|
||||
if (IsValid(v)) then
|
||||
v:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.rows = {}
|
||||
end
|
||||
|
||||
function PANEL:SetSearchEnabled(bValue)
|
||||
if (!bValue) then
|
||||
if (IsValid(self.searchEntry)) then
|
||||
self.searchEntry:Remove()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-- search entry
|
||||
self.searchEntry = self:Add("ixIconTextEntry")
|
||||
self.searchEntry:Dock(TOP)
|
||||
self.searchEntry:SetEnterAllowed(false)
|
||||
|
||||
self.searchEntry.OnChange = function(entry)
|
||||
self:FilterRows(entry:GetValue())
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:FilterRows(query)
|
||||
query = string.PatternSafe(query:lower())
|
||||
|
||||
local bEmpty = query == ""
|
||||
|
||||
for categoryName, category in pairs(self.categories) do
|
||||
category.size = 0
|
||||
category:CreateAnimation(0.5, {
|
||||
index = 21,
|
||||
target = {size = 1},
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SizeToContents()
|
||||
end
|
||||
})
|
||||
|
||||
for _, row in ipairs(category:GetChildren()) do
|
||||
local bFound = bEmpty or row:GetText():lower():find(query) or categoryName:lower():find(query)
|
||||
|
||||
row:SetVisible(true)
|
||||
row:CreateAnimation(0.5, {
|
||||
index = 21,
|
||||
target = {ixHeight = bFound and row.ixRealHeight or 0},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetTall(bFound and math.min(panel.ixHeight + 2, panel.ixRealHeight) or math.max(panel.ixHeight - 2, 0))
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
panel:SetVisible(bFound)
|
||||
|
||||
-- need this so categories are sized properly when animations are disabled - there is no guaranteed order
|
||||
-- that animations will think so we SizeToContents here. putting it here will result in redundant calls but
|
||||
-- I guess we have the performance to spare
|
||||
if (ix.option.Get("disableAnimations", false)) then
|
||||
category:SizeToContents()
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
for _, v in pairs(self.categories) do
|
||||
v:SizeToContents()
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixSettings", PANEL, "Panel")
|
||||
|
||||
hook.Add("CreateMenuButtons", "ixSettings", function(tabs)
|
||||
tabs["settings"] = {
|
||||
PopulateTabButton = function(info, button)
|
||||
local menu = ix.gui.menu
|
||||
|
||||
if (!IsValid(menu)) then
|
||||
return
|
||||
end
|
||||
|
||||
DEFINE_BASECLASS("ixMenuButton")
|
||||
button:SetZPos(9999)
|
||||
button.Paint = function(panel, width, height)
|
||||
BaseClass.Paint(panel, width, height)
|
||||
|
||||
surface.SetDrawColor(255, 255, 255, 33)
|
||||
surface.DrawRect(0, 0, width, 1)
|
||||
end
|
||||
end,
|
||||
|
||||
Create = function(info, container)
|
||||
local panel = container:Add("ixSettings")
|
||||
panel:SetSearchEnabled(true)
|
||||
|
||||
for category, options in SortedPairs(ix.option.GetAllByCategories(true)) do
|
||||
category = L(category)
|
||||
panel:AddCategory(category)
|
||||
|
||||
-- sort options by language phrase rather than the key
|
||||
table.sort(options, function(a, b)
|
||||
return L(a.phrase) < L(b.phrase)
|
||||
end)
|
||||
|
||||
for _, data in pairs(options) do
|
||||
local key = data.key
|
||||
local row = panel:AddRow(data.type, category)
|
||||
local value = ix.util.SanitizeType(data.type, ix.option.Get(key))
|
||||
|
||||
row:SetText(L(data.phrase))
|
||||
row:Populate(key, data)
|
||||
|
||||
-- type-specific properties
|
||||
if (data.type == ix.type.number) then
|
||||
row:SetMin(data.min or 0)
|
||||
row:SetMax(data.max or 10)
|
||||
row:SetDecimals(data.decimals or 0)
|
||||
end
|
||||
|
||||
row:SetValue(value, true)
|
||||
row:SetShowReset(value != data.default, key, data.default)
|
||||
row.OnValueChanged = function()
|
||||
local newValue = row:GetValue()
|
||||
|
||||
row:SetShowReset(newValue != data.default, key, data.default)
|
||||
ix.option.Set(key, newValue)
|
||||
end
|
||||
|
||||
row.OnResetClicked = function()
|
||||
row:SetShowReset(false)
|
||||
row:SetValue(data.default, true)
|
||||
|
||||
ix.option.Set(key, data.default)
|
||||
end
|
||||
|
||||
row:GetLabel():SetHelixTooltip(function(tooltip)
|
||||
local title = tooltip:AddRow("name")
|
||||
title:SetImportant()
|
||||
title:SetText(key)
|
||||
title:SizeToContents()
|
||||
title:SetMaxWidth(math.max(title:GetMaxWidth(), ScrW() * 0.5))
|
||||
|
||||
local description = tooltip:AddRow("description")
|
||||
description:SetText(L(data.description))
|
||||
description:SizeToContents()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
panel:SizeToContents()
|
||||
container.panel = panel
|
||||
end,
|
||||
|
||||
OnSelected = function(info, container)
|
||||
container.panel.searchEntry:RequestFocus()
|
||||
end
|
||||
}
|
||||
end)
|
||||
130
gamemodes/helix/gamemode/core/derma/cl_shipment.lua
Normal file
130
gamemodes/helix/gamemode/core/derma/cl_shipment.lua
Normal file
@@ -0,0 +1,130 @@
|
||||
--[[
|
||||
| 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 = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetSize(460, 360)
|
||||
self:SetTitle(L"shipment")
|
||||
self:Center()
|
||||
self:MakePopup()
|
||||
|
||||
self.scroll = self:Add("DScrollPanel")
|
||||
self.scroll:Dock(FILL)
|
||||
|
||||
self.list = self.scroll:Add("DListLayout")
|
||||
self.list:Dock(FILL)
|
||||
end
|
||||
|
||||
function PANEL:SetItems(entity, items)
|
||||
self.entity = entity
|
||||
self.items = true
|
||||
self.itemPanels = {}
|
||||
|
||||
for k, v in SortedPairs(items) do
|
||||
local itemTable = ix.item.list[k]
|
||||
|
||||
if (itemTable) then
|
||||
local item = self.list:Add("DPanel")
|
||||
item:SetTall(36)
|
||||
item:Dock(TOP)
|
||||
item:DockMargin(4, 4, 4, 0)
|
||||
|
||||
item.icon = item:Add("SpawnIcon")
|
||||
item.icon:SetPos(2, 2)
|
||||
item.icon:SetSize(32, 32)
|
||||
item.icon:SetModel(itemTable:GetModel())
|
||||
item.icon:SetHelixTooltip(function(tooltip)
|
||||
ix.hud.PopulateItemTooltip(tooltip, itemTable)
|
||||
end)
|
||||
|
||||
item.quantity = item.icon:Add("DLabel")
|
||||
item.quantity:SetSize(32, 32)
|
||||
item.quantity:SetContentAlignment(3)
|
||||
item.quantity:SetTextInset(0, 0)
|
||||
item.quantity:SetText(v)
|
||||
item.quantity:SetFont("DermaDefaultBold")
|
||||
item.quantity:SetExpensiveShadow(1, Color(0, 0, 0, 150))
|
||||
|
||||
item.name = item:Add("DLabel")
|
||||
item.name:SetPos(38, 0)
|
||||
item.name:SetSize(200, 36)
|
||||
item.name:SetFont("ixSmallFont")
|
||||
item.name:SetText(L(itemTable.name))
|
||||
item.name:SetContentAlignment(4)
|
||||
item.name:SetTextColor(color_white)
|
||||
|
||||
item.take = item:Add("DButton")
|
||||
item.take:Dock(RIGHT)
|
||||
item.take:SetText(L"take")
|
||||
item.take:SetWide(48)
|
||||
item.take:DockMargin(3, 3, 3, 3)
|
||||
item.take:SetTextColor(color_white)
|
||||
item.take.DoClick = function(this)
|
||||
net.Start("ixShipmentUse")
|
||||
net.WriteString(k)
|
||||
net.WriteBool(false)
|
||||
net.SendToServer()
|
||||
|
||||
items[k] = items[k] - 1
|
||||
|
||||
item.quantity:SetText(items[k])
|
||||
|
||||
if (items[k] <= 0) then
|
||||
item:Remove()
|
||||
items[k] = nil
|
||||
end
|
||||
|
||||
if (table.IsEmpty(items)) then
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
item.drop = item:Add("DButton")
|
||||
item.drop:Dock(RIGHT)
|
||||
item.drop:SetText(L"drop")
|
||||
item.drop:SetWide(48)
|
||||
item.drop:DockMargin(3, 3, 0, 3)
|
||||
item.drop:SetTextColor(color_white)
|
||||
item.drop.DoClick = function(this)
|
||||
net.Start("ixShipmentUse")
|
||||
net.WriteString(k)
|
||||
net.WriteBool(true)
|
||||
net.SendToServer()
|
||||
|
||||
items[k] = items[k] - 1
|
||||
|
||||
item.quantity:SetText(items[k])
|
||||
|
||||
if (items[k] <= 0) then
|
||||
item:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.itemPanels[k] = item
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Close()
|
||||
net.Start("ixShipmentClose")
|
||||
net.SendToServer()
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
if (self.items and !IsValid(self.entity)) then
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixShipment", PANEL, "DFrame")
|
||||
107
gamemodes/helix/gamemode/core/derma/cl_spawnicon.lua
Normal file
107
gamemodes/helix/gamemode/core/derma/cl_spawnicon.lua
Normal file
@@ -0,0 +1,107 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
DEFINE_BASECLASS("DModelPanel")
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.defaultEyeTarget = Vector(0, 0, 64)
|
||||
self:SetHidden(false)
|
||||
|
||||
for i = 0, 5 do
|
||||
if (i == 1 or i == 5) then
|
||||
self:SetDirectionalLight(i, Color(155, 155, 155))
|
||||
else
|
||||
self:SetDirectionalLight(i, Color(255, 255, 255))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetModel(model, skin, hidden)
|
||||
BaseClass.SetModel(self, model)
|
||||
|
||||
local entity = self.Entity
|
||||
|
||||
if (skin) then
|
||||
entity:SetSkin(skin)
|
||||
end
|
||||
|
||||
local sequence = entity:SelectWeightedSequence(ACT_IDLE)
|
||||
|
||||
if (sequence <= 0) then
|
||||
sequence = entity:LookupSequence("idle_unarmed")
|
||||
end
|
||||
|
||||
if (sequence > 0) then
|
||||
entity:ResetSequence(sequence)
|
||||
else
|
||||
local found = false
|
||||
|
||||
for _, v in ipairs(entity:GetSequenceList()) do
|
||||
if ((v:lower():find("idle") or v:lower():find("fly")) and v != "idlenoise") then
|
||||
entity:ResetSequence(v)
|
||||
found = true
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if (!found) then
|
||||
entity:ResetSequence(4)
|
||||
end
|
||||
end
|
||||
|
||||
local data = PositionSpawnIcon(entity, entity:GetPos())
|
||||
|
||||
if (data) then
|
||||
self:SetFOV(data.fov)
|
||||
self:SetCamPos(data.origin)
|
||||
self:SetLookAng(data.angles)
|
||||
end
|
||||
|
||||
entity:SetIK(false)
|
||||
entity:SetEyeTarget(self.defaultEyeTarget)
|
||||
end
|
||||
|
||||
function PANEL:SetHidden(hidden)
|
||||
if (hidden) then
|
||||
self:SetAmbientLight(color_black)
|
||||
self:SetColor(Color(0, 0, 0))
|
||||
|
||||
for i = 0, 5 do
|
||||
self:SetDirectionalLight(i, color_black)
|
||||
end
|
||||
else
|
||||
self:SetAmbientLight(Color(20, 20, 20))
|
||||
self:SetAlpha(255)
|
||||
|
||||
for i = 0, 5 do
|
||||
if (i == 1 or i == 5) then
|
||||
self:SetDirectionalLight(i, Color(155, 155, 155))
|
||||
else
|
||||
self:SetDirectionalLight(i, Color(255, 255, 255))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:LayoutEntity()
|
||||
self:RunAnimation()
|
||||
end
|
||||
|
||||
function PANEL:OnMousePressed()
|
||||
if (self.DoClick) then
|
||||
self:DoClick()
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixSpawnIcon", PANEL, "DModelPanel")
|
||||
207
gamemodes/helix/gamemode/core/derma/cl_storage.lua
Normal file
207
gamemodes/helix/gamemode/core/derma/cl_storage.lua
Normal file
@@ -0,0 +1,207 @@
|
||||
--[[
|
||||
| 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 = {}
|
||||
|
||||
AccessorFunc(PANEL, "money", "Money", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self:DockPadding(1, 1, 1, 1)
|
||||
self:SetTall(64)
|
||||
self:Dock(BOTTOM)
|
||||
|
||||
self.moneyLabel = self:Add("DLabel")
|
||||
self.moneyLabel:Dock(TOP)
|
||||
self.moneyLabel:SetFont("ixGenericFont")
|
||||
self.moneyLabel:SetText("")
|
||||
self.moneyLabel:SetTextInset(2, 0)
|
||||
self.moneyLabel:SizeToContents()
|
||||
self.moneyLabel.Paint = function(panel, width, height)
|
||||
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, ix.config.Get("color"))
|
||||
end
|
||||
|
||||
self.amountEntry = self:Add("ixTextEntry")
|
||||
self.amountEntry:Dock(FILL)
|
||||
self.amountEntry:SetFont("ixGenericFont")
|
||||
self.amountEntry:SetNumeric(true)
|
||||
self.amountEntry:SetValue("0")
|
||||
|
||||
self.transferButton = self:Add("DButton")
|
||||
self.transferButton:SetFont("ixIconsMedium")
|
||||
self:SetLeft(false)
|
||||
self.transferButton.DoClick = function()
|
||||
local amount = math.max(0, math.Round(tonumber(self.amountEntry:GetValue()) or 0))
|
||||
self.amountEntry:SetValue("0")
|
||||
|
||||
if (amount != 0) then
|
||||
self:OnTransfer(amount)
|
||||
end
|
||||
end
|
||||
|
||||
self.bNoBackgroundBlur = true
|
||||
end
|
||||
|
||||
function PANEL:SetLeft(bValue)
|
||||
if (bValue) then
|
||||
self.transferButton:Dock(LEFT)
|
||||
self.transferButton:SetText("s")
|
||||
else
|
||||
self.transferButton:Dock(RIGHT)
|
||||
self.transferButton:SetText("t")
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetMoney(money)
|
||||
local name = string.gsub(ix.util.ExpandCamelCase(ix.currency.plural), "%s", "")
|
||||
|
||||
self.money = math.max(math.Round(tonumber(money) or 0), 0)
|
||||
self.moneyLabel:SetText(string.format("%s: %d", name, money))
|
||||
end
|
||||
|
||||
function PANEL:OnTransfer(amount)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
derma.SkinFunc("PaintBaseFrame", self, width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixStorageMoney", PANEL, "EditablePanel")
|
||||
|
||||
DEFINE_BASECLASS("Panel")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "fadeTime", "FadeTime", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "frameMargin", "FrameMargin", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "storageID", "StorageID", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
if (IsValid(ix.gui.openedStorage)) then
|
||||
ix.gui.openedStorage:Remove()
|
||||
end
|
||||
|
||||
ix.gui.openedStorage = self
|
||||
|
||||
self:SetSize(ScrW(), ScrH())
|
||||
self:SetPos(0, 0)
|
||||
self:SetFadeTime(0.25)
|
||||
self:SetFrameMargin(4)
|
||||
|
||||
self.storageInventory = self:Add("ixInventory")
|
||||
self.storageInventory.bNoBackgroundBlur = true
|
||||
self.storageInventory:ShowCloseButton(true)
|
||||
self.storageInventory:SetTitle("Storage")
|
||||
self.storageInventory.Close = function(this)
|
||||
net.Start("ixStorageClose")
|
||||
net.SendToServer()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
self.storageMoney = self.storageInventory:Add("ixStorageMoney")
|
||||
self.storageMoney:SetVisible(false)
|
||||
self.storageMoney.OnTransfer = function(_, amount)
|
||||
net.Start("ixStorageMoneyTake")
|
||||
net.WriteUInt(self.storageID, 32)
|
||||
net.WriteUInt(amount, 32)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
ix.gui.inv1 = self:Add("ixInventory")
|
||||
ix.gui.inv1.bNoBackgroundBlur = true
|
||||
ix.gui.inv1:ShowCloseButton(true)
|
||||
ix.gui.inv1.Close = function(this)
|
||||
net.Start("ixStorageClose")
|
||||
net.SendToServer()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
self.localMoney = ix.gui.inv1:Add("ixStorageMoney")
|
||||
self.localMoney:SetVisible(false)
|
||||
self.localMoney:SetLeft(true)
|
||||
self.localMoney.OnTransfer = function(_, amount)
|
||||
net.Start("ixStorageMoneyGive")
|
||||
net.WriteUInt(self.storageID, 32)
|
||||
net.WriteUInt(amount, 32)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
self:SetAlpha(0)
|
||||
self:AlphaTo(255, self:GetFadeTime())
|
||||
|
||||
self.storageInventory:MakePopup()
|
||||
ix.gui.inv1:MakePopup()
|
||||
end
|
||||
|
||||
function PANEL:OnChildAdded(panel)
|
||||
panel:SetPaintedManually(true)
|
||||
end
|
||||
|
||||
function PANEL:SetLocalInventory(inventory)
|
||||
if (IsValid(ix.gui.inv1) and !IsValid(ix.gui.menu)) then
|
||||
ix.gui.inv1:SetInventory(inventory)
|
||||
ix.gui.inv1:SetPos(self:GetWide() / 2 + self:GetFrameMargin() / 2, self:GetTall() / 2 - ix.gui.inv1:GetTall() / 2)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetLocalMoney(money)
|
||||
if (!self.localMoney:IsVisible()) then
|
||||
self.localMoney:SetVisible(true)
|
||||
ix.gui.inv1:SetTall(ix.gui.inv1:GetTall() + self.localMoney:GetTall() + 2)
|
||||
end
|
||||
|
||||
self.localMoney:SetMoney(money)
|
||||
end
|
||||
|
||||
function PANEL:SetStorageTitle(title)
|
||||
self.storageInventory:SetTitle(title)
|
||||
end
|
||||
|
||||
function PANEL:SetStorageInventory(inventory)
|
||||
self.storageInventory:SetInventory(inventory)
|
||||
self.storageInventory:SetPos(
|
||||
self:GetWide() / 2 - self.storageInventory:GetWide() - 2,
|
||||
self:GetTall() / 2 - self.storageInventory:GetTall() / 2
|
||||
)
|
||||
|
||||
ix.gui["inv" .. inventory:GetID()] = self.storageInventory
|
||||
end
|
||||
|
||||
function PANEL:SetStorageMoney(money)
|
||||
if (!self.storageMoney:IsVisible()) then
|
||||
self.storageMoney:SetVisible(true)
|
||||
self.storageInventory:SetTall(self.storageInventory:GetTall() + self.storageMoney:GetTall() + 2)
|
||||
end
|
||||
|
||||
self.storageMoney:SetMoney(money)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
ix.util.DrawBlurAt(0, 0, width, height)
|
||||
|
||||
for _, v in ipairs(self:GetChildren()) do
|
||||
v:PaintManual()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Remove()
|
||||
self:SetAlpha(255)
|
||||
self:AlphaTo(0, self:GetFadeTime(), 0, function()
|
||||
BaseClass.Remove(self)
|
||||
end)
|
||||
end
|
||||
|
||||
function PANEL:OnRemove()
|
||||
if (!IsValid(ix.gui.menu)) then
|
||||
self.storageInventory:Remove()
|
||||
ix.gui.inv1:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register("ixStorageView", PANEL, "Panel")
|
||||
312
gamemodes/helix/gamemode/core/derma/cl_subpanel.lua
Normal file
312
gamemodes/helix/gamemode/core/derma/cl_subpanel.lua
Normal file
@@ -0,0 +1,312 @@
|
||||
--[[
|
||||
| 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 DEFAULT_PADDING = ScreenScale(32)
|
||||
local DEFAULT_ANIMATION_TIME = 1
|
||||
local DEFAULT_SUBPANEL_ANIMATION_TIME = 0.5
|
||||
|
||||
-- parent subpanel
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
local parent = self:GetParent()
|
||||
local padding = parent.GetPadding and parent:GetPadding() or DEFAULT_PADDING
|
||||
|
||||
self:SetSize(parent:GetWide() - (padding * 2), parent:GetTall() - (padding * 2))
|
||||
self:Center()
|
||||
end
|
||||
|
||||
function PANEL:SetTitle(text, bNoTranslation, bNoUpper)
|
||||
if (text == nil) then
|
||||
if (IsValid(self.title)) then
|
||||
self.title:Remove()
|
||||
end
|
||||
|
||||
return
|
||||
elseif (!IsValid(self.title)) then
|
||||
self.title = self:Add("DLabel")
|
||||
self.title:SetFont("ixTitleFont")
|
||||
self.title:SizeToContents()
|
||||
self.title:SetTextColor(ix.config.Get("color") or color_white)
|
||||
self.title:Dock(TOP)
|
||||
end
|
||||
|
||||
local newText = bNoTranslation and text or L(text)
|
||||
newText = bNoUpper and newText or newText:utf8upper()
|
||||
|
||||
self.title:SetText(newText)
|
||||
self.title:SizeToContents()
|
||||
end
|
||||
|
||||
function PANEL:SetLeftPanel(panel)
|
||||
self.left = panel
|
||||
end
|
||||
|
||||
function PANEL:GetLeftPanel()
|
||||
return self.left
|
||||
end
|
||||
|
||||
function PANEL:SetRightPanel(panel)
|
||||
self.right = panel
|
||||
end
|
||||
|
||||
function PANEL:GetRightPanel()
|
||||
return self.right
|
||||
end
|
||||
|
||||
function PANEL:OnSetActive()
|
||||
end
|
||||
|
||||
vgui.Register("ixSubpanel", PANEL, "EditablePanel")
|
||||
|
||||
-- subpanel parent
|
||||
DEFINE_BASECLASS("EditablePanel")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "subpanelAnimationTime", "SubpanelAnimationTime", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "leftOffset", "LeftOffset", FORCE_NUMBER)
|
||||
|
||||
function PANEL:Init()
|
||||
self.subpanels = {}
|
||||
self.childPanels = {}
|
||||
|
||||
self.currentSubpanelX = DEFAULT_PADDING
|
||||
self.targetSubpanelX = DEFAULT_PADDING
|
||||
self.padding = DEFAULT_PADDING
|
||||
self.leftOffset = 0
|
||||
|
||||
self.animationTime = DEFAULT_ANIMATION_TIME
|
||||
self.subpanelAnimationTime = DEFAULT_SUBPANEL_ANIMATION_TIME
|
||||
end
|
||||
|
||||
function PANEL:SetPadding(amount, bSetDockPadding)
|
||||
self.currentSubpanelX = amount
|
||||
self.targetSubpanelX = amount
|
||||
self.padding = amount
|
||||
|
||||
if (bSetDockPadding) then
|
||||
self:DockPadding(amount, amount, amount, amount)
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:Add(name)
|
||||
local panel = BaseClass.Add(self, name)
|
||||
|
||||
if (panel.SetPaintedManually) then
|
||||
panel:SetPaintedManually(true)
|
||||
self.childPanels[#self.childPanels + 1] = panel
|
||||
end
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
function PANEL:AddSubpanel(name)
|
||||
local id = #self.subpanels + 1
|
||||
local panel = BaseClass.Add(self, "ixSubpanel")
|
||||
panel.subpanelName = name
|
||||
panel.subpanelID = id
|
||||
panel:SetTitle(L(name))
|
||||
|
||||
self.subpanels[id] = panel
|
||||
self:SetupSubpanelReferences()
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
function PANEL:SetupSubpanelReferences()
|
||||
local lastPanel
|
||||
|
||||
for i = 1, #self.subpanels do
|
||||
local panel = self.subpanels[i]
|
||||
local nextPanel = self.subpanels[i + 1]
|
||||
|
||||
if (IsValid(lastPanel)) then
|
||||
lastPanel:SetRightPanel(panel)
|
||||
panel:SetLeftPanel(lastPanel)
|
||||
end
|
||||
|
||||
if (IsValid(nextPanel)) then
|
||||
panel:SetRightPanel(nextPanel)
|
||||
end
|
||||
|
||||
lastPanel = panel
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetSubpanelPos(id, x)
|
||||
local currentPanel = self.subpanels[id]
|
||||
|
||||
if (!currentPanel) then
|
||||
return
|
||||
end
|
||||
|
||||
local _, oldY = currentPanel:GetPos()
|
||||
currentPanel:SetPos(x, oldY)
|
||||
|
||||
-- traverse left
|
||||
while (IsValid(currentPanel)) do
|
||||
local left = currentPanel:GetLeftPanel()
|
||||
|
||||
if (IsValid(left)) then
|
||||
left:MoveLeftOf(currentPanel, self.padding + self.leftOffset)
|
||||
end
|
||||
|
||||
currentPanel = left
|
||||
end
|
||||
|
||||
currentPanel = self.subpanels[id]
|
||||
|
||||
-- traverse right
|
||||
while (IsValid(currentPanel)) do
|
||||
local right = currentPanel:GetRightPanel()
|
||||
|
||||
if (IsValid(right)) then
|
||||
right:MoveRightOf(currentPanel, self.padding)
|
||||
end
|
||||
|
||||
currentPanel = right
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetActiveSubpanel(id, length)
|
||||
if (isstring(id)) then
|
||||
for i = 1, #self.subpanels do
|
||||
if (self.subpanels[i].subpanelName == id) then
|
||||
id = i
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local activePanel = self.subpanels[id]
|
||||
|
||||
if (!activePanel) then
|
||||
return false
|
||||
end
|
||||
|
||||
if (length == 0 or !self.activeSubpanel) then
|
||||
self:SetSubpanelPos(id, self.padding + self.leftOffset)
|
||||
else
|
||||
local x, _ = activePanel:GetPos()
|
||||
local target = self.targetSubpanelX + self.leftOffset
|
||||
self.currentSubpanelX = x + self.padding + self.leftOffset
|
||||
|
||||
self:CreateAnimation(length or self.subpanelAnimationTime, {
|
||||
index = 420,
|
||||
target = {currentSubpanelX = target},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetSubpanelPos(id, panel.currentSubpanelX)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
panel:SetSubpanelPos(id, target)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
self.activeSubpanel = id
|
||||
activePanel:OnSetActive()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function PANEL:GetSubpanel(id)
|
||||
return self.subpanels[id]
|
||||
end
|
||||
|
||||
function PANEL:GetActiveSubpanel()
|
||||
return self.subpanels[self.activeSubpanel]
|
||||
end
|
||||
|
||||
function PANEL:GetActiveSubpanelID()
|
||||
return self.activeSubpanel
|
||||
end
|
||||
|
||||
function PANEL:Slide(direction, length, callback, bIgnoreConfig)
|
||||
local _, height = self:GetParent():GetSize()
|
||||
local x, _ = self:GetPos()
|
||||
local targetY = direction == "up" and 0 or height
|
||||
|
||||
self:SetVisible(true)
|
||||
|
||||
if (length == 0) then
|
||||
self:SetPos(x, targetY)
|
||||
else
|
||||
length = length or self.animationTime
|
||||
self.currentY = direction == "up" and height or 0
|
||||
|
||||
self:CreateAnimation(length or self.animationTime, {
|
||||
index = -1,
|
||||
target = {currentY = targetY},
|
||||
easing = "outExpo",
|
||||
bIgnoreConfig = bIgnoreConfig,
|
||||
|
||||
Think = function(animation, panel)
|
||||
local currentX, _ = panel:GetPos()
|
||||
|
||||
panel:SetPos(currentX, panel.currentY)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
if (direction == "down") then
|
||||
panel:SetVisible(false)
|
||||
end
|
||||
|
||||
if (callback) then
|
||||
callback(panel)
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SlideUp(...)
|
||||
self:SetMouseInputEnabled(true)
|
||||
self:SetKeyboardInputEnabled(true)
|
||||
|
||||
self:OnSlideUp()
|
||||
self:Slide("up", ...)
|
||||
end
|
||||
|
||||
function PANEL:SlideDown(...)
|
||||
self:SetMouseInputEnabled(false)
|
||||
self:SetKeyboardInputEnabled(false)
|
||||
|
||||
self:OnSlideDown()
|
||||
self:Slide("down", ...)
|
||||
end
|
||||
|
||||
function PANEL:OnSlideUp()
|
||||
end
|
||||
|
||||
function PANEL:OnSlideDown()
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
for i = 1, #self.childPanels do
|
||||
self.childPanels[i]:PaintManual()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:PaintSubpanels(width, height)
|
||||
for i = 1, #self.subpanels do
|
||||
self.subpanels[i]:PaintManual()
|
||||
end
|
||||
end
|
||||
|
||||
-- ????
|
||||
PANEL.Remove = BaseClass.Remove
|
||||
|
||||
vgui.Register("ixSubpanelParent", PANEL, "EditablePanel")
|
||||
604
gamemodes/helix/gamemode/core/derma/cl_tooltip.lua
Normal file
604
gamemodes/helix/gamemode/core/derma/cl_tooltip.lua
Normal file
@@ -0,0 +1,604 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
--- Text container for `ixTooltip`.
|
||||
-- Rows are the main way of interacting with `ixTooltip`s. These derive from
|
||||
-- [DLabel](https://wiki.garrysmod.com/page/Category:DLabel) panels, which means that making use of this panel
|
||||
-- will be largely the same as any DLabel panel.
|
||||
-- @panel ixTooltipRow
|
||||
|
||||
local animationTime = 1
|
||||
|
||||
-- panel meta
|
||||
do
|
||||
local PANEL = FindMetaTable("Panel")
|
||||
local ixChangeTooltip = ChangeTooltip
|
||||
local ixRemoveTooltip = RemoveTooltip
|
||||
local tooltip
|
||||
local lastHover
|
||||
|
||||
function PANEL:SetHelixTooltip(callback)
|
||||
self:SetMouseInputEnabled(true)
|
||||
self.ixTooltip = callback
|
||||
end
|
||||
|
||||
function ChangeTooltip(panel, ...) -- luacheck: globals ChangeTooltip
|
||||
if (!panel.ixTooltip) then
|
||||
return ixChangeTooltip(panel, ...)
|
||||
end
|
||||
|
||||
RemoveTooltip()
|
||||
|
||||
timer.Create("ixTooltip", 0.1, 1, function()
|
||||
if (!IsValid(panel) or lastHover != panel) then
|
||||
return
|
||||
end
|
||||
|
||||
tooltip = vgui.Create("ixTooltip")
|
||||
panel.ixTooltip(tooltip)
|
||||
tooltip:SizeToContents()
|
||||
end)
|
||||
|
||||
lastHover = panel
|
||||
end
|
||||
|
||||
function RemoveTooltip() -- luacheck: globals RemoveTooltip
|
||||
if (IsValid(tooltip)) then
|
||||
tooltip:Remove()
|
||||
tooltip = nil
|
||||
end
|
||||
|
||||
timer.Remove("ixTooltip")
|
||||
lastHover = nil
|
||||
|
||||
return ixRemoveTooltip()
|
||||
end
|
||||
end
|
||||
|
||||
DEFINE_BASECLASS("DLabel")
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "backgroundColor", "BackgroundColor")
|
||||
AccessorFunc(PANEL, "maxWidth", "MaxWidth", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "bNoMinimal", "MinimalHidden", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetFont("ixSmallFont")
|
||||
self:SetText(L("unknown"))
|
||||
self:SetTextColor(color_white)
|
||||
self:SetTextInset(4, 0)
|
||||
self:SetContentAlignment(4)
|
||||
self:Dock(TOP)
|
||||
|
||||
self.maxWidth = ScrW() * 0.2
|
||||
self.bNoMinimal = false
|
||||
self.bMinimal = false
|
||||
end
|
||||
|
||||
--- Whether or not this tooltip row should be displayed in a minimal format. This usually means no background and/or
|
||||
-- smaller font. You probably won't need this if you're using regular `ixTooltipRow` panels, but you should take into
|
||||
-- account if you're creating your own panels that derive from `ixTooltipRow`.
|
||||
-- @realm client
|
||||
-- @treturn bool True if this tooltip row should be displayed in a minimal format
|
||||
function PANEL:IsMinimal()
|
||||
return self.bMinimal
|
||||
end
|
||||
|
||||
--- Sets this row to be more prominent with a larger font and more noticable background color. This should usually
|
||||
-- be used once per tooltip as a title row. For example, item tooltips have one "important" row consisting of the
|
||||
-- item's name. Note that this function is a fire-and-forget function; you cannot revert a row back to it's regular state
|
||||
-- unless you set the font/colors manually.
|
||||
-- @realm client
|
||||
function PANEL:SetImportant()
|
||||
self:SetFont("ixSmallTitleFont")
|
||||
self:SetExpensiveShadow(1, color_black)
|
||||
self:SetBackgroundColor(ix.config.Get("color"))
|
||||
end
|
||||
|
||||
--- Sets the background color of this row. This should be used sparingly to avoid overwhelming players with a
|
||||
-- bunch of different colors that could convey different meanings.
|
||||
-- @realm client
|
||||
-- @color color New color of the background. The alpha is clamped to 100-255 to ensure visibility
|
||||
function PANEL:SetBackgroundColor(color)
|
||||
color = table.Copy(color)
|
||||
color.a = math.min(color.a or 255, 100)
|
||||
|
||||
self.backgroundColor = color
|
||||
end
|
||||
|
||||
--- Resizes this panel to fit its contents. This should be called after setting the text.
|
||||
-- @realm client
|
||||
function PANEL:SizeToContents()
|
||||
local contentWidth, contentHeight = self:GetContentSize()
|
||||
contentWidth = contentWidth + 4
|
||||
contentHeight = contentHeight + 4
|
||||
|
||||
if (contentWidth > self.maxWidth) then
|
||||
self:SetWide(self.maxWidth - 4) -- to account for text inset
|
||||
self:SetTextInset(4, 0)
|
||||
self:SetWrap(true)
|
||||
|
||||
self:SizeToContentsY()
|
||||
else
|
||||
self:SetSize(contentWidth, contentHeight)
|
||||
end
|
||||
end
|
||||
|
||||
--- Resizes the height of this panel to fit its contents.
|
||||
-- @internal
|
||||
-- @realm client
|
||||
function PANEL:SizeToContentsY()
|
||||
BaseClass.SizeToContentsY(self)
|
||||
self:SetTall(self:GetTall() + 4)
|
||||
end
|
||||
|
||||
--- Called when the background of this row should be painted. This will paint the background with the
|
||||
-- `DrawImportantBackground` function set in the skin by default.
|
||||
-- @realm client
|
||||
-- @number width Width of the panel
|
||||
-- @number height Height of the panel
|
||||
function PANEL:PaintBackground(width, height)
|
||||
if (self.backgroundColor) then
|
||||
derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, self.backgroundColor)
|
||||
end
|
||||
end
|
||||
|
||||
--- Called when the foreground of this row should be painted. If you are overriding this in a subclassed panel,
|
||||
-- make sure you call `ixTooltipRow:PaintBackground` at the *beginning* of your function to make its style
|
||||
-- consistent with the rest of the framework.
|
||||
-- @realm client
|
||||
-- @number width Width of the panel
|
||||
-- @number height Height of the panel
|
||||
function PANEL:Paint(width, height)
|
||||
self:PaintBackground(width, height)
|
||||
end
|
||||
|
||||
vgui.Register("ixTooltipRow", PANEL, "DLabel")
|
||||
|
||||
--- Generic information panel.
|
||||
-- Tooltips are used extensively throughout Helix: for item information, character displays, entity status, etc.
|
||||
-- The tooltip system can be used on any panel or entity you would like to show standardized information for. Tooltips
|
||||
-- consist of the parent container panel (`ixTooltip`), which is filled with rows of information (usually
|
||||
-- `ixTooltipRow`, but can be any docked panel if non-text information needs to be shown, like an item's size).
|
||||
--
|
||||
-- Tooltips can be added to panel with `panel:SetHelixTooltip()`. An example taken from the scoreboard:
|
||||
-- panel:SetHelixTooltip(function(tooltip)
|
||||
-- local name = tooltip:AddRow("name")
|
||||
-- name:SetImportant()
|
||||
-- name:SetText(client:SteamName())
|
||||
-- name:SetBackgroundColor(team.GetColor(client:Team()))
|
||||
-- name:SizeToContents()
|
||||
--
|
||||
-- tooltip:SizeToContents()
|
||||
-- end)
|
||||
-- @panel ixTooltip
|
||||
DEFINE_BASECLASS("Panel")
|
||||
PANEL = {}
|
||||
|
||||
AccessorFunc(PANEL, "entity", "Entity")
|
||||
AccessorFunc(PANEL, "mousePadding", "MousePadding", FORCE_NUMBER)
|
||||
AccessorFunc(PANEL, "bDrawArrow", "DrawArrow", FORCE_BOOL)
|
||||
AccessorFunc(PANEL, "arrowColor", "ArrowColor")
|
||||
AccessorFunc(PANEL, "bHideArrowWhenRaised", "HideArrowWhenRaised", FORCE_BOOL)
|
||||
AccessorFunc(PANEL, "bArrowFollowEntity", "ArrowFollowEntity", FORCE_BOOL)
|
||||
|
||||
function PANEL:Init()
|
||||
self.fraction = 0
|
||||
self.mousePadding = 16
|
||||
self.arrowColor = ix.config.Get("color")
|
||||
self.bHideArrowWhenRaised = true
|
||||
self.bArrowFollowEntity = true
|
||||
self.bMinimal = false
|
||||
|
||||
self.lastX, self.lastY = self:GetCursorPosition()
|
||||
self.arrowX, self.arrowY = ScrW() * 0.5, ScrH() * 0.5
|
||||
|
||||
self:SetAlpha(0)
|
||||
self:SetSize(0, 0)
|
||||
self:SetDrawOnTop(true)
|
||||
self:SetMouseInputEnabled(false)
|
||||
|
||||
self:CreateAnimation(animationTime, {
|
||||
index = 1,
|
||||
target = {fraction = 1},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.fraction * 255)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
--- Whether or not this tooltip should be displayed in a minimal format.
|
||||
-- @realm client
|
||||
-- @treturn bool True if this tooltip should be displayed in a minimal format
|
||||
-- @see ixTooltipRow:IsMinimal
|
||||
function PANEL:IsMinimal()
|
||||
return self.bMinimal
|
||||
end
|
||||
|
||||
-- ensure all children are painted manually
|
||||
function PANEL:Add(...)
|
||||
local panel = BaseClass.Add(self, ...)
|
||||
panel:SetPaintedManually(true)
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
--- Creates a new `ixTooltipRow` panel and adds it to the bottom of this tooltip.
|
||||
-- @realm client
|
||||
-- @string id Name of the new row. This is used to reorder rows if needed
|
||||
-- @treturn panel Created row
|
||||
function PANEL:AddRow(id)
|
||||
local panel = self:Add("ixTooltipRow")
|
||||
panel.id = id
|
||||
panel:SetZPos(#self:GetChildren() * 10)
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
--- Creates a new `ixTooltipRow` and adds it after the row with the given `id`. The order of the rows is set via
|
||||
-- setting the Z position of the panels, as this is how VGUI handles ordering with docked panels.
|
||||
-- @realm client
|
||||
-- @string after Name of the row to insert after
|
||||
-- @string id Name of the newly created row
|
||||
-- @treturn panel Created row
|
||||
function PANEL:AddRowAfter(after, id)
|
||||
local panel = self:AddRow(id)
|
||||
after = self:GetRow(after)
|
||||
|
||||
if (!IsValid(after)) then
|
||||
return panel
|
||||
end
|
||||
|
||||
panel:SetZPos(after:GetZPos() + 1)
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
--- Sets the entity associated with this tooltip. Note that this function is not how you get entities to show tooltips.
|
||||
-- @internal
|
||||
-- @realm client
|
||||
-- @entity entity Entity to associate with this tooltip
|
||||
function PANEL:SetEntity(entity)
|
||||
if (!IsValid(entity)) then
|
||||
self.bEntity = false
|
||||
return
|
||||
end
|
||||
|
||||
-- don't show entity tooltips if we have an entity menu open
|
||||
if (IsValid(ix.menu.panel)) then
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
if (entity:IsPlayer()) then
|
||||
local character = entity:GetCharacter()
|
||||
|
||||
if (character) then
|
||||
-- we want to group things that will most likely have backgrounds (e.g name/health status)
|
||||
hook.Run("PopulateImportantCharacterInfo", entity, character, self)
|
||||
hook.Run("PopulateCharacterInfo", entity, character, self)
|
||||
end
|
||||
else
|
||||
if (entity.OnPopulateEntityInfo) then
|
||||
entity:OnPopulateEntityInfo(self)
|
||||
else
|
||||
hook.Run("PopulateEntityInfo", entity, self)
|
||||
end
|
||||
end
|
||||
|
||||
self:SizeToContents()
|
||||
|
||||
self.entity = entity
|
||||
self.bEntity = true
|
||||
end
|
||||
|
||||
function PANEL:PaintUnder(width, height)
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
self:PaintUnder()
|
||||
|
||||
-- directional arrow
|
||||
self.bRaised = LocalPlayer():IsWepRaised()
|
||||
|
||||
if (!self.bClosing) then
|
||||
if (self.bEntity and IsValid(self.entity) and self.bArrowFollowEntity) then
|
||||
local entity = self.entity
|
||||
local position = select(1, entity:GetBonePosition(entity:LookupBone("ValveBiped.Bip01_Spine") or -1)) or
|
||||
entity:LocalToWorld(entity:OBBCenter())
|
||||
|
||||
position = position:ToScreen()
|
||||
self.arrowX = math.Clamp(position.x, 0, ScrW())
|
||||
self.arrowY = math.Clamp(position.y, 0, ScrH())
|
||||
end
|
||||
end
|
||||
|
||||
-- arrow
|
||||
if (self.bDrawArrow or (self.bDrawArrow and self.bRaised and !self.bHideArrowWhenRaised)) then
|
||||
local x, y = self:ScreenToLocal(self.arrowX, self.arrowY)
|
||||
|
||||
DisableClipping(true)
|
||||
surface.SetDrawColor(self.arrowColor)
|
||||
surface.DrawLine(0, 0, x * self.fraction, y * self.fraction)
|
||||
surface.DrawRect((x - 2) * self.fraction, (y - 2) * self.fraction, 4, 4)
|
||||
DisableClipping(false)
|
||||
end
|
||||
|
||||
-- contents
|
||||
local x, y = self:GetPos()
|
||||
|
||||
render.SetScissorRect(x, y, x + width * self.fraction, y + height, true)
|
||||
derma.SkinFunc("PaintTooltipBackground", self, width, height)
|
||||
|
||||
for _, v in ipairs(self:GetChildren()) do
|
||||
if (IsValid(v)) then
|
||||
v:PaintManual()
|
||||
end
|
||||
end
|
||||
render.SetScissorRect(0, 0, 0, 0, false)
|
||||
end
|
||||
|
||||
--- Returns the current position of the mouse cursor on the screen.
|
||||
-- @realm client
|
||||
-- @treturn number X position of cursor
|
||||
-- @treturn number Y position of cursor
|
||||
function PANEL:GetCursorPosition()
|
||||
local width, height = self:GetSize()
|
||||
local mouseX, mouseY = gui.MousePos()
|
||||
|
||||
return math.Clamp(mouseX + self.mousePadding, 0, ScrW() - width), math.Clamp(mouseY, 0, ScrH() - height)
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
if (!self.bEntity) then
|
||||
if (!vgui.CursorVisible()) then
|
||||
self:SetPos(self.lastX, self.lastY)
|
||||
|
||||
-- if the cursor isn't visible then we don't really need the tooltip to be shown
|
||||
if (!self.bClosing) then
|
||||
self:Remove()
|
||||
end
|
||||
else
|
||||
local newX, newY = self:GetCursorPosition()
|
||||
|
||||
self:SetPos(newX, newY)
|
||||
self.lastX, self.lastY = newX, newY
|
||||
end
|
||||
|
||||
self:MoveToFront() -- dragging a panel w/ tooltip will push the tooltip beneath even the menu panel(???)
|
||||
elseif (IsValid(self.entity) and !self.bClosing) then
|
||||
if (self.bRaised) then
|
||||
self:SetPos(
|
||||
ScrW() * 0.5 - self:GetWide() * 0.5,
|
||||
math.min(ScrH() * 0.5 + self:GetTall() + 32, ScrH() - self:GetTall())
|
||||
)
|
||||
else
|
||||
local entity = self.entity
|
||||
local min, max = entity:GetRotatedAABB(entity:OBBMins() * 0.5, entity:OBBMaxs() * 0.5)
|
||||
min = entity:LocalToWorld(min):ToScreen().x
|
||||
max = entity:LocalToWorld(max):ToScreen().x
|
||||
|
||||
self:SetPos(
|
||||
math.Clamp(math.max(min, max), ScrW() * 0.5 + 64, ScrW() - self:GetWide()),
|
||||
ScrH() * 0.5 - self:GetTall() * 0.5
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns an `ixTooltipRow` corresponding to the given name.
|
||||
-- @realm client
|
||||
-- @string id Name of the row
|
||||
-- @treturn[1] panel Corresponding row
|
||||
-- @treturn[2] nil If the row doesn't exist
|
||||
function PANEL:GetRow(id)
|
||||
for _, v in ipairs(self:GetChildren()) do
|
||||
if (IsValid(v) and v.id == id) then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Resizes the tooltip to fit all of the child panels. You should always call this after you are done
|
||||
-- adding all of your rows.
|
||||
-- @realm client
|
||||
function PANEL:SizeToContents()
|
||||
local height = 0
|
||||
local width = 0
|
||||
|
||||
for _, v in ipairs(self:GetChildren()) do
|
||||
if (v:GetWide() > width) then
|
||||
width = v:GetWide()
|
||||
end
|
||||
|
||||
height = height + v:GetTall()
|
||||
end
|
||||
|
||||
self:SetSize(width, height)
|
||||
end
|
||||
|
||||
function PANEL:Remove()
|
||||
if (self.bClosing) then
|
||||
return
|
||||
end
|
||||
|
||||
self.bClosing = true
|
||||
self:CreateAnimation(animationTime * 0.5, {
|
||||
target = {fraction = 0},
|
||||
easing = "outQuint",
|
||||
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.fraction * 255)
|
||||
end,
|
||||
|
||||
OnComplete = function(animation, panel)
|
||||
BaseClass.Remove(panel)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
vgui.Register("ixTooltip", PANEL, "Panel")
|
||||
|
||||
-- legacy tooltip row
|
||||
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.bMinimal = true
|
||||
self.ixAlpha = 0 -- to avoid conflicts if we're animating a non-tooltip panel
|
||||
|
||||
self:SetExpensiveShadow(1, color_black)
|
||||
self:SetContentAlignment(5)
|
||||
end
|
||||
|
||||
function PANEL:SetImportant()
|
||||
self:SetFont("ixMinimalTitleFont")
|
||||
self:SetBackgroundColor(ix.config.Get("color"))
|
||||
end
|
||||
|
||||
-- background color will affect text instead in minimal tooltips
|
||||
function PANEL:SetBackgroundColor(color)
|
||||
color = table.Copy(color)
|
||||
color.a = math.min(color.a or 255, 100)
|
||||
|
||||
self:SetTextColor(color)
|
||||
self.backgroundColor = color
|
||||
end
|
||||
|
||||
function PANEL:PaintBackground()
|
||||
end
|
||||
|
||||
vgui.Register("ixTooltipMinimalRow", PANEL, "ixTooltipRow")
|
||||
|
||||
-- legacy tooltip
|
||||
DEFINE_BASECLASS("ixTooltip")
|
||||
PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.bMinimal = true
|
||||
|
||||
-- we don't want to animate the alpha since children will handle their own animation, but we want to keep the fraction
|
||||
-- for the background to animate
|
||||
self:CreateAnimation(animationTime, {
|
||||
index = 1,
|
||||
target = {fraction = 1},
|
||||
easing = "outQuint",
|
||||
})
|
||||
|
||||
self:SetAlpha(255)
|
||||
end
|
||||
|
||||
-- we don't need the children to be painted manually
|
||||
function PANEL:Add(...)
|
||||
local panel = BaseClass.Add(self, ...)
|
||||
panel:SetPaintedManually(false)
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
function PANEL:AddRow(id)
|
||||
local panel = self:Add("ixTooltipMinimalRow")
|
||||
panel.id = id
|
||||
panel:SetZPos(#self:GetChildren() * 10)
|
||||
|
||||
return panel
|
||||
end
|
||||
|
||||
function PANEL:Paint(width, height)
|
||||
self:PaintUnder()
|
||||
|
||||
derma.SkinFunc("PaintTooltipMinimalBackground", self, width, height)
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
-- remove any panels that shouldn't be shown in a minimal tooltip
|
||||
for _, v in ipairs(self:GetChildren()) do
|
||||
if (v.bNoMinimal) then
|
||||
v:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
BaseClass.SizeToContents(self)
|
||||
self:SetPos(ScrW() * 0.5 - self:GetWide() * 0.5, ScrH() * 0.5 + self.mousePadding)
|
||||
|
||||
-- we create animation here since this is the only function that usually gets called after all the rows are populated
|
||||
local children = self:GetChildren()
|
||||
|
||||
-- sort by z index so we can animate them in order
|
||||
table.sort(children, function(a, b)
|
||||
return a:GetZPos() < b:GetZPos()
|
||||
end)
|
||||
|
||||
local i = 1
|
||||
local count = table.Count(children)
|
||||
|
||||
for _, v in ipairs(children) do
|
||||
v.ixAlpha = v.ixAlpha or 0
|
||||
|
||||
v:CreateAnimation((animationTime / count) * i, {
|
||||
easing = "inSine",
|
||||
target = {ixAlpha = 255},
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.ixAlpha)
|
||||
end
|
||||
})
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
DEFINE_BASECLASS("Panel")
|
||||
function PANEL:Remove()
|
||||
if (self.bClosing) then
|
||||
return
|
||||
end
|
||||
|
||||
self.bClosing = true
|
||||
|
||||
-- we create animation here since this is the only function that usually gets called after all the rows are populated
|
||||
local children = self:GetChildren()
|
||||
|
||||
-- sort by z index so we can animate them in order
|
||||
table.sort(children, function(a, b)
|
||||
return a:GetZPos() > b:GetZPos()
|
||||
end)
|
||||
|
||||
local duration = animationTime * 0.5
|
||||
local i = 1
|
||||
local count = table.Count(children)
|
||||
|
||||
for _, v in ipairs(children) do
|
||||
v.ixAlpha = v.ixAlpha or 255
|
||||
|
||||
v:CreateAnimation(duration / count * i, {
|
||||
target = {ixAlpha = 0},
|
||||
Think = function(animation, panel)
|
||||
panel:SetAlpha(panel.ixAlpha)
|
||||
end
|
||||
})
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
self:CreateAnimation(duration, {
|
||||
target = {fraction = 0},
|
||||
OnComplete = function(animation, panel)
|
||||
BaseClass.Remove(panel)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
vgui.Register("ixTooltipMinimal", PANEL, "ixTooltip")
|
||||
Reference in New Issue
Block a user