diff --git a/lua/autorun/cmenu_load.lua b/lua/autorun/cmenu_load.lua new file mode 100644 index 0000000..b3b8a59 --- /dev/null +++ b/lua/autorun/cmenu_load.lua @@ -0,0 +1,37 @@ + + PIS = {} + + local function Load() + local loader = Nexus:Loader() + loader:SetName("CMenu") + loader:SetColor(Color(48, 100, 255)) + loader:SetAcronym("PIS") + loader:RegisterAcronym() + loader:SetLoadDirectory("infl_cmenu") + loader:Load("config", "SHARED", true) + loader:Load("core", "SHARED", true) + loader:Load("vgui", "CLIENT", true) + loader:Load("misc", "SHARED", true) + loader:Load("gamemodes", "SHARED", true) + + for i, v in pairs(PIS.Gamemodes) do + if (v:GetDetectionCondition()()) then + PIS.Gamemode = v + end + end + + if (!PIS.Gamemode) then + for i, v in pairs(PIS.Gamemodes) do + if (v:GetID() == "backup") then + PIS.Gamemode = v + + break + end + end + end + + loader:Register() + end + + if (Nexus) then Load() + else hook.Add("Nexus.PostLoaded", "CMenu", Load) end diff --git a/lua/autorun/nexus_load.lua b/lua/autorun/nexus_load.lua new file mode 100644 index 0000000..5acf08c --- /dev/null +++ b/lua/autorun/nexus_load.lua @@ -0,0 +1,27 @@ +Nexus = {} + +hook.Run("Nexus.PreLoaded") + +if (CLIENT) then + include("nexus_framework/core/load.lua") +elseif (SERVER) then + include("nexus_framework/core/load.lua") + AddCSLuaFile("nexus_framework/core/load.lua") +end + +local loader = Nexus:Loader() +loader:SetName("Framework") +loader:SetColor(Color(208, 53, 53)) +loader:SetAcronym("Framework") +loader:RegisterAcronym() +loader:SetLoadDirectory("nexus_framework") +loader:Load("core", "SHARED", true, { + ["load.lua"] = true +}) +loader:Load("database", "SERVER", true) +loader:Load("vgui", "CLIENT") +loader:Load("vgui/modules", "CLIENT", true) +loader:Load("vgui/components", "CLIENT", true) +loader:Register() + +hook.Run("Nexus.PostLoaded") \ No newline at end of file diff --git a/lua/infl_cmenu/config/config.lua b/lua/infl_cmenu/config/config.lua new file mode 100644 index 0000000..9299836 --- /dev/null +++ b/lua/infl_cmenu/config/config.lua @@ -0,0 +1,186 @@ + +PIS.Config = {} +PIS.Config.Pings = {} +PIS.Config.PingsSorted = {} +PIS.Config.PingSets = {} + +local Color = Color + +local yellow = Color(200, 200, 30) +local red = Color(200, 30, 30) +local blue = Color(30, 30, 200) +local ocean = Color(0,133,255) +local green = Color(30,200,30) +local info = Color(92,107,192) +local white = Color(255,255,255) +local black = Color(0,0,0) +local redy = Color(236, 136, 22) +local greeny = Color(87, 255, 3) +local violet = Color(160, 0 , 160) + +function PIS.Config:AddMenu(id, mat, text, col, commands,cc) + self.Pings[id] = { + mat = mat, + text = text, + color = col, + commands = commands, + customcheck = cc, + id = id + } + + table.insert(self.PingsSorted, id) +end + + +PIS.Config.Colors = { + Green = Color(46, 204, 113), + Red = Color(230, 58, 64) +} +PIS.Config.BackgroundColor = Color(44, 44, 44) +PIS.Config.HighlightTabColor = Color(200, 25, 35) +PIS.Config.HighlightColor = Color(193, 70, 40) + +PIS.Config.DefaultSettings = { + PingSound = 1, + PingOffscreen = 1, + PingPulsating = 2, + PingOverhead = 1, + PingIconSet = 1, + Scale = 1, + DetectionScale = 1, + PingAvatarVertices = 30, + WheelDelay = 0.1, + WheelKey = MOUSE_MIDDLE, + InteractionKey = KEY_F, + WheelBlur = 1, + WheelScale = 1, + WheelMonochrome = 1 +} + + +PIS.Config.WheelColors = { + [1] = { "Disabled", "none" }, + [2] = { "White", color_white }, + [3] = { "Blue", blue }, + [4] = { "Red", red }, + [5] = { "Green", Color(128, 177, 11) } +} + + +--[[ + +Синтаксис AddMenu: + +1. id - делать таким же, как и название +2. иконка - писать только название, берется из materials/ping_system/ +3. название - чек 1 +4. цвет иконки - цвета есть на самом верху, но ничего не мешает тебе сделать их самому с помощью Color +5. действие: если сделать это массивом (чек Деньги), то кнопка будет включать в себя меню, если функцией - одно действие +6(необ). customCheck - в каких случаях игроку доступна кнопка + +]] + + + +local LeadCP = {} + +hook.Add("loadCustomDarkRPItems","inflexible.CMenu",function() + + LeadCP = { + [TEAM_MAYOR] = true, + [TEAM_CHIEF] = true, + } + +end) + + + +--[[------------------------------------------------------------------------- + +Обьяснение функций +PIS.OpenTextBox - Заголовок,Вопрос игроку, команда (здесб пользователь вписывает нужные данные в поле) +PIS.OpenPlyBox - Заголовок, Вопрос игроку, команда (в отличии от OpenTextBox, здесь пользователь выбирает игрока из списка) +PIS.OpenPlyReasonBox - Заголовок,Вопрос игроку,Второй вопрос игроку, команда (полезно для команд по типу wanted, demote etc) + +---------------------------------------------------------------------------]] + +PIS.Config:AddMenu("Деньги", "money", "Деньги", green, { + + {name = "Передать деньги", mat = "money_cheque", col = green, func = function() PIS.OpenTextBox("Передача денег","Сколько денег вы хотите дать этому игроку?", "/give") end}, + {name = "Бросить деньги", mat = "money_drop", col = green, func = function() PIS.OpenTextBox("Бросить деньги на пол","Сколько денег вы собираетесь бросить на пол?","/dropmoney") end}, + --{name = "Выписать чек", mat = "money", col = green, func = function() PIS.OpenPlyReasonBox("Выписать чек","Кому выписать чек?","На какую сумму?","/cheque") end}, + {name = "Продать предмет", mat = "sell", col = green, func = function() RunConsoleCommand("say","/sell") end}, + + +}) + +PIS.Config:AddMenu("RP Действия", "action", "RP Действия", red, { + + + {name = "Выбросить оружие", mat = "gun", col = red, func = function() RunConsoleCommand("say","/drop") end}, + {name = "Реклама", mat = "broadcast", col = red, func = function() PIS.OpenTextBox("Реклама","Укажите текст рекламы","/advert") end}, + {name = "Казино", mat = "casino", col = red, func = function() RunConsoleCommand("mcasino") end}, + {name = "Dark WEB", mat = "darkweb", col = red, func = function() RunConsoleCommand("say", "!darkweb") end}, + {name = "Заказать убийство", mat = "hitman", col = red, func = function() RunConsoleCommand("say","/rhit_openmenu") end}, + {name = "Уволить", mat = "demote", col = red, func = function() PIS.OpenPlyReasonBox("Уволить игрока","Кого вы хотите уволить?","Укажите корректную причину увольнения","/demote") end}, + + -- + -- + + +}) + +PIS.Config:AddMenu("Экстренные службы", "emergency", "Экстренные службы", blue, { + + {name = "Полиция", mat = "police", col = blue, func = function() inflexible.CallGuard.DoCall("cp") end}, + {name = "Скорая помощь", mat = "medic", col = red, func = function() inflexible.CallGuard.DoCall("medic") end}, + + + +}) + +PIS.Config:AddMenu("Остальное", "mill", "Остальное", violet, { + + + {name = "Продать все двери", mat = "door", col = violet, func = function() RunConsoleCommand("say","/unownalldoors") end}, + {name = "Смена имени", mat = "name", col = violet, func = function() PIS.OpenTextBox("Смена имени персонажа","Как Вас будут звать?","/rpname") end}, + {name = "Случайное число", mat = "dice", col = violet, func = function() RunConsoleCommand("say","/roll") end}, + {name = "Третье лицо", mat = "third_person", col = violet, func = function() RunConsoleCommand("third_person") end}, + {name = "Пожаловаться на игрока", mat = "admin", col = violet, func = function() RunConsoleCommand("say","/r") end}, + {name = "Emotes", mat = "emotes", col = violet, func = function() RunConsoleCommand("emotes") end}, + + +}) + + + + +PIS.Config:AddMenu("Flex-Pass", "money_bag", "Flex-Pass", yellow, function() RunConsoleCommand("say","/donate") end) + +PIS.Config:AddMenu("Ссылки", "info", "Ссылки", info, { + + + + + {name = "Вконтакте", mat = "vk", col = ocean, func = function() inflexible.util:OpenURL("https://vk.com/im") end}, + {name = "Контент", mat = "steam", col = black, func = function() inflexible.util:OpenURL("https://steamcommunity.com/sharedfiles") end}, + {name = "Discord", mat = "discord", col = white, func = function() inflexible.util:OpenURL("https://discord.gg/11111") end}, + {name = "Правила", mat = "document", col = white, func = function() inflexible.util:OpenURL("https://docs.google.com/document/d111") end}, + + +}) + +PIS.Config:AddMenu("Меню полиции", "police", "Меню полиции", blue, { + + + {name = "Подать в розыск", mat = "police", col = red, func = function() PIS.OpenPlyReasonBox("Обьявить в розыск","Кого обьявить в розыск?","По какой причине?","/wanted") end}, + {name = "Выдать ордер", mat = "police", col = red, func = function() PIS.OpenPlyReasonBox("Выдача ордера","Кому вы хотите выдать ордер?","Обьясните свой выбор.","/warrant") end}, + {name = "Выдать лицензию", mat = "license", col = white, func = function() RunConsoleCommand("say", "/givelicense") end, customcheck = function(ply) return inflexible.LeadCP[ply:Team()] end}, + {name = "Начать ком. час", mat = "warning", col = redy, func = function() RunConsoleCommand("say", "/lockdown") end, customcheck = function(ply) return ply:isMayor() && !GetGlobalBool("DarkRP_LockDown") end}, + {name = "Окончить ком. час", mat = "warning", col = greeny, func = function() RunConsoleCommand("say", "/unlockdown") end, customcheck = function(ply) return ply:isMayor() && GetGlobalBool("DarkRP_LockDown") end}, + +},function(ply) return ply:isCP() end) + + + +PIS.Config:AddMenu("Список заказов", "hitman", "Список заказов", red, function() RunConsoleCommand("say","/hits") end, function(ply) return ply:Team() == TEAM_HITMAN end) \ No newline at end of file diff --git a/lua/infl_cmenu/core/gamemodes.lua b/lua/infl_cmenu/core/gamemodes.lua new file mode 100644 index 0000000..e175672 --- /dev/null +++ b/lua/infl_cmenu/core/gamemodes.lua @@ -0,0 +1,22 @@ +PIS.Gamemodes = {} + +local GAMEMODE = {} + +AccessorFunc(GAMEMODE, "m_name", "Name") +AccessorFunc(GAMEMODE, "m_id", "ID") +AccessorFunc(GAMEMODE, "m_viewCondition", "ViewCondition") +AccessorFunc(GAMEMODE, "m_pingCondition", "PingCondition") +AccessorFunc(GAMEMODE, "m_commandCondition", "CommandCondition") +AccessorFunc(GAMEMODE, "m_interactionCondition", "InteractionCondition") +AccessorFunc(GAMEMODE, "m_detectionCondition", "DetectionCondition") +AccessorFunc(GAMEMODE, "m_players", "Players") +AccessorFunc(GAMEMODE, "m_onDeath", "OnDeath") +AccessorFunc(GAMEMODE, "m_displaySubtitle", "SubtitleDisplay") + +function GAMEMODE:Register() + PIS.Gamemodes[self:GetID()] = self +end + +function PIS:GetGamemode() + return table.Copy(GAMEMODE) +end \ No newline at end of file diff --git a/lua/infl_cmenu/core/sql.lua b/lua/infl_cmenu/core/sql.lua new file mode 100644 index 0000000..15300a9 --- /dev/null +++ b/lua/infl_cmenu/core/sql.lua @@ -0,0 +1,63 @@ +if (SERVER) then return end + +function PIS:GetServerID() + return game.GetIPAddress() or "192.168.0.0:27015" +end + +function PIS:CreateSQLTables() + sql.Query([[ + CREATE TABLE IF NOT EXISTS nexus_psi_settings ( + id TEXT(50), + settings TEXT(4000), + PRIMARY KEY (id) + ) + ]]) +end + +function PIS:LoadSettings(ply) + local id = sql.SQLStr(PIS:GetServerID()) + + local result = sql.Query([[ + SELECT * FROM nexus_psi_settings + WHERE id = ]] .. id + ) + + if (istable(result) and #result > 0) then + PIS:SetSettings(ply, util.JSONToTable(result[1].settings)) + end +end + +function PIS:SaveSettings(ply) + local settings = sql.SQLStr(util.TableToJSON(self:GetSettings(ply))) + local id = sql.SQLStr(PIS:GetServerID()) + + local result = sql.Query([[ + SELECT * FROM nexus_psi_settings + WHERE id = ]] .. id + ) + + if (istable(result) and #result > 0) then + sql.Query([[ + UPDATE nexus_psi_settings + SET settings = ]] .. settings .. [[ + WHERE id = ]] .. id + ) + else + sql.Query([[ + INSERT INTO nexus_psi_settings (id, settings) + VALUES (]] .. id .. [[, ]] .. settings .. [[) + ]]) + end +end + +hook.Add("Initialize", "PIS.SQLCreation", function() + PIS:CreateSQLTables() +end) + +hook.Add("HUDPaint", "PIS.LoadSettings", function() + hook.Remove("HUDPaint", "PIS.LoadSettings") + + timer.Simple(3, function() + PIS:LoadSettings(LocalPlayer()) + end) +end) \ No newline at end of file diff --git a/lua/infl_cmenu/gamemodes/backup.lua b/lua/infl_cmenu/gamemodes/backup.lua new file mode 100644 index 0000000..5490be7 --- /dev/null +++ b/lua/infl_cmenu/gamemodes/backup.lua @@ -0,0 +1,38 @@ +local GAMEMODE = PIS:GetGamemode() +GAMEMODE:SetName("Backup") +GAMEMODE:SetID("backup") +GAMEMODE:SetDetectionCondition(function() + + return false +end) +GAMEMODE:SetPlayers(function(author) + local tbl = {} + + for i, v in pairs(player.GetAll()) do + if (v == author) then continue end + + table.insert(tbl, v) + end + + return tbl +end) +GAMEMODE:SetSubtitleDisplay(function(player) + return player:GetUserGroup():sub(1, 1):upper() .. player:GetUserGroup():sub(2) +end) +GAMEMODE:SetViewCondition(function(author, target) + return true +end) +GAMEMODE:SetPingCondition(function(author) + return author:Alive() +end) +GAMEMODE:SetCommandCondition(function(author) + return true +end) +GAMEMODE:SetInteractionCondition(function(author) + return author:Alive() +end) +GAMEMODE:SetOnDeath(function(author) + +end) + +GAMEMODE:Register() diff --git a/lua/infl_cmenu/gamemodes/darkrp.lua b/lua/infl_cmenu/gamemodes/darkrp.lua new file mode 100644 index 0000000..3414f6b --- /dev/null +++ b/lua/infl_cmenu/gamemodes/darkrp.lua @@ -0,0 +1,50 @@ +local GAMEMODE = PIS:GetGamemode() +GAMEMODE:SetName("DarkRP") +GAMEMODE:SetID("darkrp") +GAMEMODE:SetDetectionCondition(function() + return DarkRP +end) +GAMEMODE:SetPlayers(function(author) + local tbl = {} + + for i, v in pairs(player.GetAll()) do + if (v == author) then continue end + for _, tbl in pairs(PIS.Config.RPTeamViews) do + if (table.HasValue(tbl, team.GetName(v:Team()))) then + table.insert(tbl, v) + + break + end + end + table.insert(tbl, v) + end + + return tbl +end) +GAMEMODE:SetSubtitleDisplay(function(player) + return team.GetName(player:Team()) +end) +GAMEMODE:SetViewCondition(function(author, target) + for i, v in pairs(PIS.Config.RPTeamViews) do + if (table.HasValue(v, team.GetName(target:Team()))) then + return true + end + end +end) +GAMEMODE:SetPingCondition(function(author) + return author:Alive() +end) +GAMEMODE:SetCommandCondition(function(author, target) + local authorAuth = PIS.Config.RPTeamAuthority[team.GetName(author:Team())] or 1 + local targetAuth = PIS.Config.RPTeamAuthority[team.GetName(target:Team())] or 1 + + return authorAuth > targetAuth +end) +GAMEMODE:SetInteractionCondition(function(author) + return author:Alive() +end) +GAMEMODE:SetOnDeath(function(author) + +end) + +GAMEMODE:Register() diff --git a/lua/infl_cmenu/gamemodes/ttt.lua b/lua/infl_cmenu/gamemodes/ttt.lua new file mode 100644 index 0000000..b48463f --- /dev/null +++ b/lua/infl_cmenu/gamemodes/ttt.lua @@ -0,0 +1,38 @@ +local GAMEMODE = PIS:GetGamemode() +GAMEMODE:SetName("Trouble in Terrorist Town") +GAMEMODE:SetID("ttt") +GAMEMODE:SetDetectionCondition(function() + return engine.ActiveGamemode() == "terrortown" +end) +GAMEMODE:SetPlayers(function(author) + local tbl = {} + + for i, v in pairs(player.GetAll()) do + if (v == author) then continue end + if (!v:IsTraitor()) then continue end + + table.insert(tbl, v) + end + + return tbl +end) +GAMEMODE:SetViewCondition(function(author, target) + return target:IsTraitor() +end) +GAMEMODE:SetPingCondition(function(author) + return author:Alive() and author:IsTraitor() +end) +GAMEMODE:SetCommandCondition(function(author) + return true +end) +GAMEMODE:SetSubtitleDisplay(function(player) + return player:GetUserGroup():sub(1, 1):upper() .. player:GetUserGroup():sub(2) +end) +GAMEMODE:SetInteractionCondition(function(author) + return author:Alive() +end) +GAMEMODE:SetOnDeath(function(author) + +end) + +GAMEMODE:Register() diff --git a/lua/infl_cmenu/misc/api.lua b/lua/infl_cmenu/misc/api.lua new file mode 100644 index 0000000..70f8fb8 --- /dev/null +++ b/lua/infl_cmenu/misc/api.lua @@ -0,0 +1,59 @@ +function PIS:SetSettings(ply, tbl) + ply.pingsSettings = tbl +end + +function PIS:SetSetting(ply, setting, value, ignoreSave) + ply.pingsSettings[setting] = value + + if (ignoreSave) then return end + + PIS:SaveSettings(ply) +end + +function PIS:GetSettings(ply) + if (!ply.pingsSettings) then + ply.pingsSettings = PIS.Config.DefaultSettings + end + + return ply.pingsSettings +end + +PING_STATUS_DEFAULT = 0 +PING_STATUS_CONFIRMED = 1 +PING_STATUS_REJECTED = 2 + +PING_COMMAND_CONFIRM = 0 + +function PIS:GetKeyName(key) + if (!isnumber(key)) then return "UNKNOWN KEY" end + + if (key >= MOUSE_MIDDLE) then + if (key == MOUSE_MIDDLE) then + return "MIDDLE MOUSE" + elseif (key == MOUSE_4) then + return "MOUSE 4" + elseif (key == MOUSE_5) then + return "MOUSE 5" + elseif (key == MOUSE_WHEEL_UP) then + return "MOUSE WHEEL UP" + elseif (key == MOUSE_WHEEL_DOWN) then + return "MOUSE WHEEL DOWN" + else + return "UNKNOWN MOUSE" + end + else + return input.GetKeyName(key) and input.GetKeyName(key):upper() or "UNKNOWN KEY" + end +end + + +PIS.PingCache = {} +function PIS:GetPingIcon(mat) + + if not PIS.PingCache[mat] then + PIS.PingCache[mat] = Material("inflexible/"..mat..".png","smooth") + end + + return PIS.PingCache[mat] + +end diff --git a/lua/infl_cmenu/misc/download.lua b/lua/infl_cmenu/misc/download.lua new file mode 100644 index 0000000..2ce093e --- /dev/null +++ b/lua/infl_cmenu/misc/download.lua @@ -0,0 +1,6 @@ +if (CLIENT) then return end + +resource.AddFile("resources/fonts/TT Squares Condensed Regular") +resource.AddFile("resources/fonts/TT Lakes Compressed Black") +resource.AddFile("resources/fonts/TT Lakes Condensed Bold") +resource.AddFile("resources/fonts/TT Lakes Medium") \ No newline at end of file diff --git a/lua/infl_cmenu/networking/client.lua b/lua/infl_cmenu/networking/client.lua new file mode 100644 index 0000000..bb9fb0d --- /dev/null +++ b/lua/infl_cmenu/networking/client.lua @@ -0,0 +1,23 @@ +net.Receive("PIS.PlacePing", function(len) + local tbl = net.ReadTable() + + if (PIS:IsMuted(LocalPlayer(), tbl.author)) then return end + + PIS:AddPing(tbl.author, tbl.id, tbl.pos, tbl.directedAt) +end) + +net.Receive("PIS.RemovePing", function(len) + PIS:RemovePing(net.ReadEntity()) +end) + +net.Receive("PIS.ReactPing", function(len) + local tbl = net.ReadTable() + local ping = PIS:GetPing(tbl.id) + + if (!ping) then return end + + if (tbl.command == PING_COMMAND_CONFIRM) then + ping.status = PING_STATUS_CONFIRMED + end +end) + diff --git a/lua/infl_cmenu/networking/server.lua b/lua/infl_cmenu/networking/server.lua new file mode 100644 index 0000000..be1a5e7 --- /dev/null +++ b/lua/infl_cmenu/networking/server.lua @@ -0,0 +1,65 @@ +util.AddNetworkString("PIS.PlacePing") +util.AddNetworkString("PIS.RemovePing") +util.AddNetworkString("PIS.ReactPing") + +net.Receive("PIS.PlacePing", function(len, ply) + if (!PIS.Gamemode:GetPingCondition()(ply)) then return end + + local tbl = net.ReadTable() + local id = tbl.id + local pos = tbl.pos + local directedAt = tbl.directedAt + + if (IsValid(tbl.directedAt)) then + if (!PIS.Gamemode:GetCommandCondition()(ply, tbl.directedAt)) then return end + end + + PIS:AddPing(ply, id, pos, directedAt) + + net.Start("PIS.PlacePing") + net.WriteTable({ + author = ply, + id = id, + pos = pos, + directedAt = directedAt + }) + net.Send(PIS.Gamemode:GetPlayers()(ply)) +end) + +net.Receive("PIS.RemovePing", function(len, ply) + if (!PIS.Gamemode:GetPingCondition()(ply)) then return end + + local ping = PIS:GetPing(ply) + + if (ping) then + PIS:RemovePing(ply) + + net.Start("PIS.RemovePing") + net.WriteEntity(ply) + + net.Broadcast() + end +end) + +net.Receive("PIS.ReactPing", function(len, ply) + if (!PIS.Gamemode:GetInteractionCondition()(ply)) then return end + + local command = net.ReadUInt(8) + local ping = PIS:GetPing(pingId) + + if (ping) then + local command = tbl.command + if (!command) then return end + + if (command == PING_COMMAND_CONFIRM and ping.directedAt == ply) then + ping.status = PING_STATUS_CONFIRMED + + net.Start("PIS.ReactPing") + net.WriteTable({ + id = ply:SteamID64(), + command = command + }) + net.Send(PIS.Gamemode:GetPlayers()(ply)) + end + end +end) \ No newline at end of file diff --git a/lua/infl_cmenu/ping_rendering/render_2d.lua b/lua/infl_cmenu/ping_rendering/render_2d.lua new file mode 100644 index 0000000..576f991 --- /dev/null +++ b/lua/infl_cmenu/ping_rendering/render_2d.lua @@ -0,0 +1,217 @@ +local framework = Nexus:ClassManager("Framework") +local _draw = framework:Class("Draw") +local anim = framework:Class("Animations") +local panels = framework:Class("Panels") + +surface.CreateFont("Nexus.PingSystem.3D.Type", { + font = "Montserrat", + size = 24, + weight = 800 +}) + +surface.CreateFont("Nexus.PingSystem.3D.Cancel", { + font = "Montserrat", + size = 24, + weight = 500 +}) + +surface.CreateFont("Nexus.PingSystem.3D.CancelButton", { + font = "Montserrat", + size = 20, + weight = 1200 +}) + + +surface.CreateFont("Nexus.PingSystem.3D.Dist", { + font = "Montserrat", + size = 20, + weight = 500 +}) + +function PIS:Render2D() + local ply = LocalPlayer() + local plyPos = ply:GetPos() + + local lookingAt = self:IsLookingAtPing() + if (lookingAt) then + local settings = PIS:GetSettings(ply) + local ping = self.Pings[lookingAt.key] + if (!IsValid(ping.author)) then + PIS:RemovePing(lookingAt.key) + end + local pingTbl = self.Config.Pings[ping.ping] + local tr = ply:GetEyeTrace() + local hitPos = tr.HitPos + hitPos = LocalToWorld(Vector(0, -50, -15), Angle(0, 0, 0), hitPos, ply:GetAngles()) + local sPos = ping.pos:ToScreen() + local x = ScrW() / 2 + 75--100 + local y = ScrH() / 2 - 75--100 + local sX = sPos.x + local sY = sPos.y + + local dist = plyPos:Distance(ping.pos) + local distY = math.Clamp(dist * 0.5 >= 525 and dist * 0.5 - 525 or 0, 0, dist * 0.3) + local scale = math.max(dist / 250, 1) + local matSize = 128 * scale + local matX = (matSize * -1) / 2 + local matY = -10 + matSize * -1 + matY = math.abs(matY - (distY * math.Clamp(scale * 0.4, 0, 1.5))) + local distModifier = ((ply:GetFOV() * 2) / dist) + local matYOffset = matSize * 0.1 * distModifier + matY * 0.1 * distModifier + draw.NoTexture() + surface.SetDrawColor(color_black) + local tbl = { + { x = sX, y = sY - matYOffset }, + { x = sX + 50, y = sY - matYOffset - 50 }, + { x = sX + 50, y = sY - matYOffset } + } + --surface.DrawPoly(tbl) + --surface.DrawRect(sX, sY, 20, 20) + + surface.SetFont("Nexus.PingSystem.3D.Type") + local tw, th = surface.GetTextSize(ping.directedAt and pingTbl.command .. " " or pingTbl.text) + local dist = math.Round(plyPos:Distance(ping.pos) * (0.0254 / (4/3))) .. "m" + surface.SetFont("Nexus.PingSystem.3D.Type") + local _tw = surface.GetTextSize(dist) + local height = 2 + local width = 10 + tw + _tw + surface.SetFont("Nexus.PingSystem.3D.Cancel") + local isLocalPlayer = LocalPlayer() == ping.author + local cancelStr = isLocalPlayer and "CANCEL" or ping.author:Nick() + local tw, th = surface.GetTextSize(cancelStr) + local topWidth = 10 + tw + 5 + if (isLocalPlayer) then + local _tw, th = surface.GetTextSize(PIS:GetKeyName(settings.InteractionKey)) + topWidth = topWidth + _tw + 10 + end + local status = ping.status + local str = status == PING_STATUS_CONFIRMED and "Confirmed" or "Confirm - " .. PIS:GetKeyName(settings.InteractionKey) + + surface.SetFont("Nexus.PingSystem.3D.Type") + if (ping.directedAt == LocalPlayer()) then + local str = status == PING_STATUS_CONFIRMED and "Confirmed" or "Confirm - " .. PIS:GetKeyName(settings.InteractionKey) + local _tw, th = surface.GetTextSize(str) + + topWidth = topWidth + _tw + (isLocalPlayer and -10 or 10) + elseif (ping.directedAt) then + local str = status == PING_STATUS_CONFIRMED and "Confirmed" or "Unconfirmed" + local _tw, th = surface.GetTextSize(str) + + topWidth = topWidth + _tw + (isLocalPlayer and -10 or 10) + end + width = math.max(topWidth, width) + local lineX = x + + surface.SetFont("Nexus.PingSystem.3D.Type") + + local commandStr = (ping.directedAt and pingTbl.command .. " " or pingTbl.text) + local tw, th = surface.GetTextSize(commandStr) + _draw:Call("ShadowText", commandStr, "Nexus.PingSystem.3D.Type", x, y + 4, pingTbl.color, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + if (ping.directedAt) then + local _tw = surface.GetTextSize(ping.directedAt:Nick()) + local col = ping.status == PING_STATUS_DEFAULT and Color(215, 215, 215) + or ping.status == PING_STATUS_CONFIRMED and PIS.Config.Colors.Green + or ping.status == PING_STATUS_REJECTED and PIS.Config.Colors.Red + _draw:Call("ShadowText", ping.directedAt:Nick(), "Nexus.PingSystem.3D.Type", x + tw, y + 4, col, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + tw = tw + _tw + end + _draw:Call("ShadowText", dist, "Nexus.PingSystem.3D.Dist", x + tw + 5, y + 4 + 2, pingTbl.color, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + + surface.SetFont("Nexus.PingSystem.3D.Cancel") + local _tw = surface.GetTextSize(cancelStr) + _draw:Call("ShadowText", cancelStr, "Nexus.PingSystem.3D.Cancel", x, y - 4, Color(215, 215, 215), TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM) + if (!isLocalPlayer) then + x = x + _tw + 5 + end + + surface.SetFont("Nexus.PingSystem.3D.Type") + local tw, th = surface.GetTextSize(cancelStr) + local _tw, _th = surface.GetTextSize(PIS:GetKeyName(settings.InteractionKey)) + local __tw, __th = surface.GetTextSize(cancelStr) + + if (isLocalPlayer) then + x = x + tw + 5 + draw.RoundedBox(6, x, math.ceil(y - 4 - th), _tw + 8, th, Color(215, 215, 215)) + draw.SimpleText(PIS:GetKeyName(settings.InteractionKey), "Nexus.PingSystem.3D.CancelButton", x + _tw / 2 + 4, y - th / 2 - 4, Color(62, 62, 62), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + x = x + _tw + 8 + 5 + end + + if (ping.directedAt == LocalPlayer()) then + local status = ping.status + local str = status == PING_STATUS_CONFIRMED and "Confirmed" or "Confirm - " .. PIS:GetKeyName(settings.InteractionKey) + local col = status == PING_STATUS_CONFIRMED and PIS.Config.Colors.Green or Color(183, 183, 183) + local textCol = color_black + + local _tw, th = surface.GetTextSize(str) + + draw.RoundedBox(6, x, math.ceil(y - 4 - __th), _tw + 8, __th, col) + draw.SimpleText(str, "Nexus.PingSystem.3D.CancelButton", x + _tw / 2 + 4, y - __th / 2 - 4, textCol, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + + x = x + _tw + 5 + elseif (ping.directedAt) then + local status = ping.status + local str = status == PING_STATUS_CONFIRMED and "Confirmed" or "Unconfirmed" + local col = status == PING_STATUS_CONFIRMED and PIS.Config.Colors.Green or PIS.Config.Colors.Red + local textCol = status == PING_STATUS_CONFIRMED and Color(222, 222, 222) or color_black + + local _tw, th = surface.GetTextSize(str) + + draw.RoundedBox(6, x, math.ceil(y - 4 - __th), _tw + 8, __th, col) + draw.SimpleText(str, "Nexus.PingSystem.3D.CancelButton", x + _tw / 2 + 4, y - __th / 2 - 4, textCol, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + + x = x + _tw + 5 + end + + draw.RoundedBox(0, lineX - 5, y, width, height, pingTbl.color) + end +end + +hook.Add("HUDPaint", "PIS.RenderPings", function() + PIS:Render2D() +end) + +hook.Add("PostDrawHUD", "PIS.RenderOffscreenPings", function() + local settings = PIS:GetSettings(LocalPlayer()) + if (settings.PingOffscreen == 3) then return end + + for i, v in pairs(PIS.Pings) do + local ping = PIS.Config.Pings[v.ping] + if (!ping) then continue end + if (settings.PingOffscreen == 2 and v.directedAt != LocalPlayer()) then continue end + local mat = PIS:GetPingIcon(v.ping) + local col = ping.color + local pos = v.pos + local sPos = pos:ToScreen() + local x = sPos.x + local y = sPos.y + + local size = 64 + + local drawPing + + if (x < -50) then + drawPing = true + elseif (y < -20) then + drawPing = true + elseif (y > ScrH() + 80) then + drawPing = true + elseif (x > ScrW() + 50) then + drawPing = true + end + + if (!drawPing) then continue end + + local x = math.Clamp(x - size / 2, 16, ScrW() - 16 - size) + local y = math.Clamp(y, 16, ScrH() - size - 16) + + _draw:Call("BlurHUD", x - 2, y - 2, size + 2, size) + + surface.SetMaterial(mat) + surface.SetDrawColor(0, 0, 0, 255) + for i = 1, 3 do + surface.DrawTexturedRect(x - 1, y - 1, size + 2, size + 2) + end + surface.SetDrawColor(col) + surface.DrawTexturedRect(x, y, size, size) + end +end) \ No newline at end of file diff --git a/lua/infl_cmenu/ping_rendering/render_3d.lua b/lua/infl_cmenu/ping_rendering/render_3d.lua new file mode 100644 index 0000000..3008058 --- /dev/null +++ b/lua/infl_cmenu/ping_rendering/render_3d.lua @@ -0,0 +1,223 @@ +local recFilled = Material("ping_system/rec_fill.png", "smooth") +local gradientDown = Material("vgui/gradient_down") + +local framework = Nexus:ClassManager("Framework") +local _draw = framework:Class("Draw") + +-- Missing texture, so why not go with it? +local loadingMaterial = Material("vgui/error.png") + +function PIS:Render3D() + local ply = LocalPlayer() + local settings = PIS:GetSettings(ply) + local pos = ply:GetPos() + local ang = ply:EyeAngles() + --local lookPos = ply:EyePos() + --local lookAimVector = ply:GetAimVector() + + for i, v in pairs(self.Pings) do + local ping = self.Config.Pings[v.ping] + if (!ping) then continue end + if (!IsValid(v.author)) then + PIS:RemovePing(i) + + continue + end + if (v.directedAt and !IsValid(v.directedAt)) then + PIS:RemovePing(i) + + continue + end + + local mat = PIS:GetPingIcon(v.ping) + local col = ping.color + + --local intersect = v.pos - lookPos + --local normalized = intersect:GetNormalized() + --local dotProduct = normalized:Dot(lookAimVector) + + local pingPos = v.pos + -- Get angle between the two positions + local diffAng = (pos - pingPos):GetNormalized():Angle() + local pingAng = Angle(0, 0, 0) + + -- Rotate axises + pingAng:RotateAroundAxis(pingAng:Forward(), 90) + pingAng:RotateAroundAxis(pingAng:Right(), 90 - ang.y) + pingAng:RotateAroundAxis(pingAng:Forward(), -ang.x) + + --if (dotProduct < dotProductNeed) then + -- mat = recFilled + --end + + cam.Start3D2D(pingPos, pingAng, 0.1) + cam.IgnoreZ(true) + + local dist = pos:Distance(pingPos) + local distY = math.Clamp(dist * 0.5 >= 525 and dist * 0.5 - 525 or 0, 0, dist * 0.3) + local scale = math.max(dist / 250, 1) + local matSize = 128 * scale + matSize = matSize * settings.Scale or 1 + + local x = (matSize * -1) / 2 + local y = -10 + matSize * -1 + y = y - (distY * math.Clamp(scale * 0.4, 1, 1.5)) + + v.PingStartAnimationEnd = v.PingStartAnimationEnd or CurTime() + 0.4 + + surface.SetMaterial(mat) + if (CurTime() < v.PingStartAnimationEnd) then + local frac = math.TimeFraction(v.PingStartAnimationEnd - 0.4, v.PingStartAnimationEnd, CurTime()) + + local startSize = matSize * 0.6 + local endSize = matSize * 2 + local alpha = 255 - (frac * 255) + local size = Lerp(frac, startSize, endSize) + + local y = -10 - size / 2 - matSize / 2 - (distY * math.Clamp(scale * 0.4, 1, 1.5)) + surface.SetDrawColor(ColorAlpha(col, alpha)) + surface.DrawTexturedRect((size * -1) / 2, y, size, size) + elseif (settings.PingPulsating == 1 or v.dontDrawIcon or (!v.dontDrawIcon and v.directedAt == ply and v.status == PING_STATUS_DEFAULT)) then + if (settings.PingPulsating != 3) then + v.PingScatterAnimation = v.PingScatterAnimation or CurTime() + 1 + + -- Radiate + local frac = math.TimeFraction(v.PingScatterAnimation - 1, v.PingScatterAnimation, CurTime()) + local startSize = matSize * 0.6 + local endSize = v.directedAt == ply and matSize * 2 or matSize * 1.8 + local alpha = 255 - (frac * 255) + local size = Lerp(frac, startSize, endSize) + + local y = -10 - size / 2 - matSize / 2 - (distY * math.Clamp(scale * 0.4, 1, 1.5)) + surface.SetDrawColor(ColorAlpha(col, alpha)) + surface.DrawTexturedRect((size * -1) / 2, y, size, size) + + if (frac >= 0.99) then + v.PingScatterAnimation = nil + frac = 0 + end + end + end + + surface.SetMaterial(mat) + surface.SetDrawColor(color_black) + surface.DrawTexturedRect(x - 4 * scale, y - 4 * scale, matSize + 8 * scale, matSize + 8 * scale) + surface.DrawTexturedRect(x + 4 * scale, y + 4 * scale, matSize - 8 * scale, matSize - 8 * scale) + surface.SetDrawColor(col) + surface.DrawTexturedRect(x, y, matSize, matSize) + + -- Draw icon above lul + if (v.directedAt) then + --local icon = v.status == PING_STATUS_DEFAULT and questionMark + -- or v.status == PING_STATUS_CONFIRMED and confirmed + -- or v.status == PING_STATUS_REJECTED and rejected + local col = v.status == PING_STATUS_DEFAULT and Color(215, 215, 215) + or v.status == PING_STATUS_CONFIRMED and PIS.Config.Colors.Green + or v.status == PING_STATUS_REJECTED and PIS.Config.Colors.Red + local size = matSize * 0.15 + local vertices = 4 + local playerIcon = PIS.Avatars[v.directedAt:IsBot() and "BOT" or v.directedAt:SteamID64()] or loadingMaterial + local width = size * 2 + + if (settings.PingOverhead == 1) then + _draw:Call("Circle", x + width * 2 - size / 2 - matSize * 0.02, y - width * 0.75 - matSize * 0.04, size * 1.18, settings.PingAvatarVertices or 30, color_black) + _draw:Call("Circle", x + width * 2 - size / 2 - matSize * 0.02, y - width * 0.75 - matSize * 0.04, size * 1.1, settings.PingAvatarVertices or 30, col) + _draw:Call("MaskInclude", function() + _draw:Call("Circle", x + width * 2 - size / 2 - matSize * 0.02, y - width * 0.75 - matSize * 0.04, size * 0.9, settings.PingAvatarVertices or 30, col) + end, function() + surface.SetMaterial(playerIcon) + surface.SetDrawColor(255, 255, 255) + surface.DrawTexturedRect(x + matSize / 2 - size, y - width * 0.75 - size - matSize * 0.05, width, width) + end) + else + size = matSize * 0.2 + width = size * 2 + surface.SetMaterial(recFilled) + surface.SetDrawColor(color_black) + surface.DrawTexturedRect(x + matSize / 2 - size, y - width * 0.75 - size - matSize * 0.05, width, width) + surface.SetDrawColor(col) + width = width * 0.88 + surface.DrawTexturedRect(x + matSize / 2 - size + -1 + 4, y - width * 0.75 - size - matSize * 0.05 - 2, width, width) + end + end + + local gY = y + matSize + 12.5 * scale + local gW = 12.5 * scale + local gX = x - gW / 2 + matSize / 2 + local gH = distY * math.Clamp(scale * 0.4, 1, 1.5) + + _draw:Call("MaskInclude", function() + draw.NoTexture() + surface.DrawPoly({ + { x = gX - 2 * scale, y = gY - 2 * scale }, + { x = gX + gW + 2 * scale, y = gY - 2 * scale }, + { x = gX + gW / 2, y = gY + gH + 2 * scale } + }) + end, function() + surface.SetMaterial(gradientDown) + surface.SetDrawColor(0, 0, 0, 255) + surface.DrawTexturedRect(gX - 2 * scale, gY - 2 * scale, gW + 4 * scale, gH + 4 * scale) + end) + + _draw:Call("MaskInclude", function() + draw.NoTexture() + surface.DrawPoly({ + { x = gX, y = gY }, + { x = gX + gW, y = gY }, + { x = gX + gW / 2, y = gY + gH } + }) + end, function() + surface.SetMaterial(gradientDown) + surface.SetDrawColor(col) + surface.DrawTexturedRect(gX, gY, gW, gH) + end) + + + cam.IgnoreZ(false) + cam.End3D2D() + end + + /* + local lookingAt = self:IsLookingAtPing() + if (lookingAt) then + local ping = self.Pings[lookingAt.key] + local dist = pos:Distance(ping.pos) + local distY = math.Clamp(dist * 0.5 >= 525 and dist * 0.5 - 525 or 0, 0, dist * 0.3) + local scale = math.max(dist / 250, 1) + local matSize = 128 * scale + matSize = matSize * settings.Scale + local x = (matSize * -1) / 2 + local y = -10 + matSize * -1 + y = y - (distY * math.Clamp(scale * 0.4, 1, 1.5)) + x = x + matSize + y = y - matSize + + local tr = ply:GetEyeTrace() + local hitPos = tr.HitPos + hitPos = LocalToWorld(Vector(0, -50, -15), Angle(0, 0, 0), hitPos, ply:GetAngles()) + + local z = 14.5 * scale + ((distY * math.Clamp(scale * 0.4, 1, 1.5)) / 11) + for i = 1, 10 do + --render.DrawLine( + -- LocalToWorld(Vector(0, 0.2, z + (i * 0.05)), Angle(0, 0, 0), ping.pos, LocalPlayer():GetAngles()), + -- LocalToWorld(Vector(0, 0.2, 0), Angle(0, 0, 0), hitPos, LocalPlayer():GetAngles()), + -- color_black + --) + --render.DrawLine( + -- LocalToWorld(Vector(0, -0.2, z + (i * 0.05)), Angle(0, 0, 0), ping.pos, LocalPlayer():GetAngles()), + -- LocalToWorld(Vector(0, -0.2, 0), Angle(0, 0, 0), hitPos, LocalPlayer():GetAngles()), + -- color_black + --) + --render.DrawLine( + -- LocalToWorld(Vector(0, 0, z + (i * 0.05)), Angle(0, 0, 0), ping.pos, LocalPlayer():GetAngles()), + -- hitPos, + -- self.Config.Pings[ping.ping].color + --) + end + end + */ +end + +hook.Add("PostDrawTranslucentRenderables", "PIS.RenderPings", function() + PIS:Render3D() +end) \ No newline at end of file diff --git a/lua/infl_cmenu/ping_rendering/render_input.lua b/lua/infl_cmenu/ping_rendering/render_input.lua new file mode 100644 index 0000000..8c08ae2 --- /dev/null +++ b/lua/infl_cmenu/ping_rendering/render_input.lua @@ -0,0 +1,39 @@ +hook.Add("PlayerButtonDown", "PIS.RegisterInput", function(ply, btn) + local settings = PIS:GetSettings(ply) + + if (btn == settings.InteractionKey or btn == settings.WheelKey and !IsValid(PIS.RadialMenu)) then + PIS:HandleInput(btn) + end +end) + +function PIS:RemovePing(id) + self.Pings[id] = nil +end + +function PIS:HandleInput(btn) + local lookingAt = self:IsLookingAtPing() + local settings = PIS:GetSettings(LocalPlayer()) + local ply = LocalPlayer() + if (lookingAt) then + local ping = self.Pings[lookingAt.key] + local pingTbl = self.Config.Pings[ping.ping] + + if (btn == settings.InteractionKey) then + if (ping.directedAt == ply and ping.status == PING_STATUS_DEFAULT) then + ping.status = PING_STATUS_CONFIRMED + + net.Start("PIS.ReactPing") + net.WriteTable({ + id = lookingAt.key, + command = PING_COMMAND_CONFIRM + }) + net.SendToServer() + elseif (ping.author == ply) then + PIS:RemovePing(lookingAt.key) + + net.Start("PIS.RemovePing") + net.SendToServer() + end + end + end +end \ No newline at end of file diff --git a/lua/infl_cmenu/ping_rendering/render_utility.lua b/lua/infl_cmenu/ping_rendering/render_utility.lua new file mode 100644 index 0000000..e885c62 --- /dev/null +++ b/lua/infl_cmenu/ping_rendering/render_utility.lua @@ -0,0 +1,66 @@ +function PIS:PingIsInBox(pos, pingX, pingY) + local centerX = ScrW() / 2 + local centerY = ScrH() / 2 + local ySize = 45 + local xSize = 45 + + local ply = LocalPlayer() + local dist = ply:GetPos():Distance(pos) + local distModifier = math.Clamp((6000 - dist) / 6000, 0.6, 1) + local scale = distModifier + if (dist < 200) then + scale = math.Clamp(200 / dist, 1, 2.5) + end + + ySize = ySize * scale + xSize = xSize * scale + + xSize = xSize * PIS:GetSettings(ply).DetectionScale + ySize = ySize * PIS:GetSettings(ply).DetectionScale + + local leftX = centerX - xSize + local leftY = centerY - ySize + local rightX = centerX + xSize + local rightY = centerY + ySize + + --draw.RoundedBox(6, leftX, leftY, xSize * 2, ySize * 2, Color(0, 0, 0, 150)) + + if (pingX >= leftX and pingY >= leftY and pingX <= rightX and pingY <= rightY) then + return PIS:Get2DDistance(Vector(centerX, centerY), Vector(pingX, pingY)) + end + + return false +end + +function PIS:IsLookingAtPing() + local ply = LocalPlayer() + local pos = ply:GetPos() + local lookPos = ply:GetEyeTrace().HitPos + local lookAimVector = ply:GetAimVector() + local tbl = {} + + for i, v in pairs(self.Pings) do + local sPos = v.pos:ToScreen() + local x = sPos.x + local y = sPos.y + local dist = self:PingIsInBox(v.pos, x, y) + if (!dist) then continue end + + table.insert(tbl, { dist = dist, key = i }) + end + + table.sort(tbl, function(a, b) + return b.dist > a.dist + end) + + return tbl[1] +end + +gameevent.Listen("player_connect") +hook.Add("player_connect", "PIS.RemovePings", function(data) + local sid64 = util.SteamIDTo64(data.networkid) + + if (PIS:GetPing(sid64)) then + PIS:RemovePing(sid64) + end +end) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/circle_menu.lua b/lua/infl_cmenu/vgui/circle_menu.lua new file mode 100644 index 0000000..b226ec1 --- /dev/null +++ b/lua/infl_cmenu/vgui/circle_menu.lua @@ -0,0 +1,450 @@ +local framework = Nexus:ClassManager("Framework") +local _draw = framework:Class("Draw") +local anim = framework:Class("Animations") +local panels = framework:Class("Panels") + +-- Register panel +local PANEL = {} + +local rightClick = Material("inflexible/rmb.png","smooth") +local leftClick = Material("inflexible/lmb.png","smooth") + +local soundHover = Sound("ping_system/hover2.wav") +local soundSelect = Sound("ping_system/accept2.wav") +local yellow = Color(253, 177, 3) +local red = Color(223, 70, 24) +local green = Color(129, 163, 19) + +local surface = surface + +local sin = math.sin +local cos = math.cos +local mrad = math.rad +local abs = math.abs + + inflexible = inflexible or {} + inflexible.hud = inflexible.hud or {} + + local surface = surface + local Lerp = Lerp + local draw = draw + local math = math + + local shadow = 1 + local ico_wide = 32 + local font = "base" + local meta = FindMetaTable("Player") + + local black = Color(0,0,0,200) + local lp = LocalPlayer + + + --[[------------------------------------------------------------------------- + ---------------------------------------------------------------------------]] + + local function ss(px) return ScreenScale(px)/3 end + + function inflexible.hud:CreateFont(name,size,font,weight,scale) + scale = scale or false + if scale then size = ss(size) end + + surface.CreateFont("infl.hud."..name,{font = font, size = size, weight = weight, extended = true}) + surface.CreateFont("infl.hud."..name.."_blur",{font = font, size = size, weight = weight, extended = true, blursize = 1}) + end + + function inflexible.hud:GetFont(name) return "infl.hud."..name,"infl.hud."..name.."_blur" end + + --[[------------------------------------------------------------------------- + ---------------------------------------------------------------------------]] + + function inflexible.hud:DrawText(text,font,x,y,col,xa,ya) + local font_def,font_blur = inflexible.hud:GetFont(font) + xa = xa or 0 + ya = ya or 0 + + draw.SimpleText(text,font_blur,x+shadow,y+shadow,ColorAlpha(color_black,col.a),xa,ya) + return draw.SimpleText(text,font_def,x,y,col,xa,ya) + end + + --[[------------------------------------------------------------------------- + ---------------------------------------------------------------------------]] + + function inflexible.LerpColor(t,col1,col2) + return Color ( + Lerp(t,col1.r,col2.r), + Lerp(t,col1.g,col2.g), + Lerp(t,col1.b,col2.b), + Lerp(t,col1.a,col2.a) + ) + end + + --[[------------------------------------------------------------------------- + ---------------------------------------------------------------------------]] + +function PANEL:SetContents(name) + local settings = PIS:GetSettings(LocalPlayer()) + + self.SectionsTbl = {} + self.ContentType = name + + for i, v in pairs(self.SectionsTbl) do + if (!ispanel(v)) then continue end + + v:Remove() + end + + if name == "pings" then + for i, v in ipairs(PIS.Config.PingsSorted) do + local ping = PIS.Config.Pings[v] + if (!ping) then continue end + if ping.customcheck and not ping.customcheck(LocalPlayer()) then continue end + self:AddSection(ping.text, ping.mat, settings.WheelMonochrome != 1 and PIS.Config.WheelColors[settings.WheelMonochrome][2] or ping.color, ping.commands, v) + end + elseif name == "commands" and istable(self.DisplayCommand) then + local ping = self.DisplayCommand + for k,t in pairs(ping) do if t.customcheck and not t.customcheck(LocalPlayer()) then continue end self:AddSection(t.name, t.mat, settings.WheelMonochrome != 1 and PIS.Config.WheelColors[settings.WheelMonochrome][2] or t.col, t.func, t.name) end + end + + self.Sections = #self.SectionsTbl +end + +function PANEL:PerformLayout(w, h) + local sectionSize = 360 / self.Sections + local rad = self.Radius * 0.4 + for i, v in ipairs(self.SectionsTbl) do + if (!ispanel(v)) then continue end + + local ang = (i - 1) * sectionSize + ang = mrad(ang) + local size = self.Sections > 12 and self.Radius * 2 / self.Sections or (56 * self.Settings.WheelScale) + if (self.selectedArea and self.selectedArea + 1 == i) then + size = size * 1.285 + end + local r = self.Radius - rad / 2 + local sin = sin(ang) * r + local cos = cos(ang) * r + local x = self.Center.X - size / 2 + sin + local y = self.Center.Y - size / 2 - cos + + v:SetSize(size, size) + v:SetPos(x, y) + end +end + +function PANEL:Init() + PIS.RadialMenu = self + + self.Settings = PIS:GetSettings(LocalPlayer()) + + surface.CreateFont("Nexus.PingSystem.Ping", { + font = "Roboto", + size = math.Round(46 * self.Settings.WheelScale), + weight = 600 + }) + + surface.CreateFont("Nexus.PingSystem.Name", { + font = "Roboto", + size = math.Round(30 * self.Settings.WheelScale), + weight = 600 + }) + + surface.CreateFont("Nexus.PingSystem.Info", { + font = "Roboto", + size = math.Round(26 * self.Settings.WheelScale) + }) + + self.Radius = 325 * self.Settings.WheelScale + + self.Center = { + X = ScrW() / 2, + Y = ScrH() / 2 + } + + self.SectionsTbl = {} + + self:SetContents("pings") + + self.CircleColor = Color(0, 0, 0, 0) + self:SetAlpha(0) + self:AlphaTo(255, 0.2) + + self.selectable = true + + self:MakePopup() + self:SetKeyboardInputEnabled(false) + + self.InnerArcColor = color_white + self.OuterArcColor = color_white + + local rad = self.Radius * 0.4 + + self.MainCircle = _draw:Call("PrecacheCircle",self.Center.X, self.Center.Y, self.Radius,360,90) + self.MainArc = _draw:Call("PrecacheArc",self.Center.X, self.Center.Y, self.Radius,rad, 0, 360, 1) + self.MainArc2 = _draw:Call("PrecacheArc",self.Center.X, self.Center.Y, self.Radius - rad, 3, 0, 360, 1) + --_draw:Call("Arc", self.Center.X, self.Center.Y, self.Radius - rad, 3, 0, 360, 1, Color(188, 188, 188)) + --_draw:Call("Arc", self.Center.X, self.Center.Y, self.Radius, rad, 0, 360, 1, Color(0, 0, 0, 150)) + --_draw:Call("Circle", self.Center.X, self.Center.Y, self.Radius, 90, Color(0, 0, 0, 150)) + +end + +function PANEL:Select(id) + if (self.FadingOut) then return end + + surface.PlaySound(soundSelect) + + local tbl = self.SectionsTbl[id + 1] + if isfunction(tbl.command) then tbl.command() self:Close() return + else + self.DisplayCommand = self.SectionsTbl[self.selectedArea+1].command + self:SetContents("commands") + self.Command = self.selectedTbl + self.selectedTbl = self.SectionsTbl[self.selectedArea + 1] or self.SectionsTbl[1] + end + + self.selectable = false + timer.Simple(.1,function() if ValidPanel(self) then self.selectable = true end end) + +end + +function PANEL:AddSection(name, mat, col, command, id) + table.insert(self.SectionsTbl, { + name = name, + mat = mat, + col = col, + command = command, + id = id + }) +end + +function PANEL:Think() + + commandKeyDown = input.IsMouseDown(MOUSE_RIGHT) + if commandKeyDown and self.selectable and self.ContentType == "commands" then + + + self:SetContents("pings") + self.Command = function() end + self.selectedTbl = self.SectionsTbl[self.selectedArea+1] + self.DisplayCommand = nil + surface.PlaySound(soundHover) + timer.Simple(.1,function() if ValidPanel(self) then self.selectable = true end end) + + end + + if not input.IsMouseDown(MOUSE_LEFT) then return end + if self.selectedArea and self.HasMovedSlightly and self.selectable then + self:Select(self.selectedArea) + + return + end + +end + + +function PANEL:Close() + if (self.FadingOut) then return end + + self.FadingOut = true + self:AlphaTo(0, 0.2, nil, function() + self:Remove() + end) +end + +function PANEL:Paint(w, h) + local rad = self.Radius * 0.4 + local settings = PIS:GetSettings(LocalPlayer()) + + if (settings.WheelBlur == 1) then + _draw:Call("MaskInclude", function() + _draw:Call("CachedArc",self.MainArc,Color(0, 0, 0, 150)) + end, function() + _draw:Call("Blur", self, 6, 4) + + draw.NoTexture() + _draw:Call("CachedCircle",self.MainCircle,Color(0, 0, 0, 150)) + --_draw:Call("Circle", self.Center.X, self.Center.Y, self.Radius, 90, Color(0, 0, 0, 150)) + end) + else + _draw:Call("Arc", self.Center.X, self.Center.Y, self.Radius, rad, 0, 360, 1, Color(0, 0, 0, 245)) + end + + _draw:Call("CachedArc",self.MainArc2,Color(188, 188, 188)) + --_draw:Call("Arc", self.Center.X, self.Center.Y, self.Radius - rad, 3, 0, 360, 1, Color(188, 188, 188)) + + -- Found somewhere else, don't remember where but it's a workshop addon + local cursorAng = 180 - ( -- 360 + math.deg( + math.atan2( + gui.MouseX() - self.Center.X, + gui.MouseY() - self.Center.Y + ) + ) + --+ 180 + ) + + if (self.HasMovedSlightly) then + _draw:Call("Circle", self.Center.X, self.Center.Y, self.Radius - rad - 3, 90, self.CircleColor) + local sectionSize = 360 / self.Sections + + local selectedArea = abs(cursorAng + sectionSize / 2) / sectionSize + selectedArea = math.floor(selectedArea) + if (selectedArea >= self.Sections) then + selectedArea = 0 + end + + if (self.selectedArea != selectedArea) then + if (#self.SectionsTbl > 0) then + surface.PlaySound(soundHover) + end + + self.selectedTbl = self.SectionsTbl[selectedArea + 1] + + self:InvalidateLayout() + end + + self.InnerArcColor = inflexible.LerpColor(FrameTime()*10,self.InnerArcColor,self.selectedTbl.col) + self.OuterArcColor = self.selectedTbl.col + + self.selectedArea = selectedArea + local selectedAng = selectedArea * sectionSize + local outerArcScale = math.Round(4 * self.Settings.WheelScale) + _draw:Call("Arc", self.Center.X, self.Center.Y, self.Radius + outerArcScale, outerArcScale, 90 - selectedAng - sectionSize / 2, 90 - selectedAng + sectionSize / 2, 1, self.OuterArcColor) + _draw:Call("Arc", self.Center.X, self.Center.Y, self.Radius, rad, 90 - selectedAng - sectionSize / 2, 90 - selectedAng + sectionSize / 2, 1, Color(0, 0, 0, 180)) + + local innerArcScale = math.Round(6 * self.Settings.WheelScale) + _draw:Call("Arc", self.Center.X, self.Center.Y, self.Radius - rad + innerArcScale * 2, innerArcScale, -cursorAng - 21 + 90 - 0, -cursorAng + 90 + 21, 1, self.InnerArcColor) + + if (self.selectedTbl) then + inflexible.hud:DrawText(self.selectedTbl.name, "notify", w / 2, h / 2 - 24, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM) + --_draw:Call("ShadowText",self.selectedTbl.name, "Nexus.PingSystem.Name", w / 2, h / 2 - 24, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM) + + local str = istable(self.selectedTbl.command) and "Открыть меню" or "Выбрать" + surface.SetFont("Nexus.PingSystem.Info") + local tw, th = surface.GetTextSize(str) + local iconSize = th + local x = w / 2 - iconSize / 2 - tw / 2 - 4 + local y = h / 2 + 20 + th / 2 + + surface.SetDrawColor(color_white) + surface.SetMaterial(leftClick) + surface.DrawTexturedRect(x, y, iconSize, iconSize) + + inflexible.hud:DrawText(str, "icon", x + iconSize + 8, y + 1, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + --_draw:Call("ShadowText", str, "Nexus.PingSystem.Info", x + iconSize + 8, y + 1, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + + if self.ContentType == "commands" then + + local str = "Назад" + surface.SetFont("Nexus.PingSystem.Info") + local tw, th = surface.GetTextSize(str) + + local iconSize = th + local x = w / 2 - iconSize / 2 - tw / 2 - 4 + local y = h / 2 + (56 * self.Settings.WheelScale) + th / 2 + surface.SetDrawColor(color_white) + surface.SetMaterial(rightClick) + surface.DrawTexturedRect(x, y, iconSize, iconSize) + inflexible.hud:DrawText(str,"icon",x + iconSize + 8, y, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + --_draw:Call("ShadowText", str, "Nexus.PingSystem.Info", x + iconSize + 8, y, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + + + end + + end + else + + local xDist = abs(self.Center.X - gui.MouseX()) + local yDist = abs(self.Center.Y - gui.MouseY()) + -- Euclidean distance + local dist = math.sqrt(xDist ^ 2 + yDist ^ 2) + if (dist > 20) then + self.HasMovedSlightly = true + self:Anim():Call("AnimateColor", self, "CircleColor", Color(0, 0, 0, 200)) + end + end + + local sectionSize = 360 / self.Sections + for i, v in ipairs(self.SectionsTbl) do + if (ispanel(v)) then continue end + + local ang = (i - 1) * sectionSize + ang = mrad(ang) + local size = (56 * self.Settings.WheelScale) + if (self.selectedArea and self.selectedArea + 1 == i) then + size = (72 * self.Settings.WheelScale) + end + local r = self.Radius - rad / 2 + local sin = sin(ang) * r + local cos = cos(ang) * r + local x = self.Center.X - size / 2 + sin + local y = self.Center.Y - size / 2 - cos + + surface.SetMaterial(PIS:GetPingIcon(v.mat)) + surface.SetDrawColor(v.col or color_white) + surface.DrawTexturedRect(x, y, size, size) + end +end + +vgui.Register("PIS.Radial", PANEL) + +function PIS:OpenRadialMenu() + local frame = panels:Call("Create", "PIS.Radial") + frame:SetSize(ScrW(), ScrH()) + frame:SetPos(0, 0) +end + +local KeyDown + +hook.Add("OnContextMenuOpen","infl.Cmenu",function() if not ValidPanel(PIS.RadialMenu) then PIS:OpenRadialMenu() end end) +hook.Add("OnContextMenuClose","infl.Cmenu",function() if ValidPanel(PIS.RadialMenu) then PIS.RadialMenu:Close() end end) + + inflexible.hud:CreateFont("icon",26,"Roboto",400) + inflexible.hud:CreateFont("base",36,"Consolas",700) + inflexible.hud:CreateFont("small",20,"Roboto",700) + inflexible.hud:CreateFont("notify",26,"Roboto",700) + inflexible.hud:CreateFont("safezone",40,"Roboto",700) + inflexible.hud:CreateFont("safezone_small",30,"Roboto",500) + inflexible.hud:CreateFont("entitydisplay",170,"Roboto",1600) + inflexible.hud:CreateFont("wsel",24,"Roboto",600) + inflexible.hud:CreateFont("wsel-small",19,"Roboto",500) + inflexible.hud:CreateFont("ban",52,"Consolas",800) + + +--[[ +hook.Add("CreateMove", "PIS.CircleMenu", function() + local settings = PIS:GetSettings(LocalPlayer()) + local code = settings.WheelKey + local isDown + local isUp + if (code >= MOUSE_MIDDLE) then + isDown = input.WasMousePressed(code) + isUp = input.WasMouseReleased(code) + else + isDown = input.WasKeyPressed(code) + isUp = input.WasKeyReleased(code) + end + + if (KeyDown and !isUp and !isDown) then + if (CurTime() - KeyDown >= settings.WheelDelay) then + local focus = vgui.GetKeyboardFocus() + if (!IsValid(focus) and !IsValid(PIS.RadialMenu)) then + PIS:OpenRadialMenu() + end + end + elseif (!KeyDown and isDown) then + KeyDown = CurTime() + elseif (KeyDown and isUp) then + KeyDown = nil + end + + if (IsValid(PIS.RadialMenu)) then + local rightClick = input.WasMouseReleased(MOUSE_RIGHT) + local leftClick = input.WasMouseReleased(MOUSE_LEFT) + if (rightClick) then + hook.Run("Nexus.PingSystem.RightClick") + elseif (leftClick) then + hook.Run("Nexus.PingSystem.LeftClick") + end + end +end) +]] \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/elements/boolean.lua b/lua/infl_cmenu/vgui/elements/boolean.lua new file mode 100644 index 0000000..410ced5 --- /dev/null +++ b/lua/infl_cmenu/vgui/elements/boolean.lua @@ -0,0 +1,77 @@ +local PANEL = {} + +surface.CreateFont("Nexus.PingSystem.Settings.Boolean", { + font = "TT Lakes Medium", + size = 20 +}) + +function PANEL:SetOptions(tbl) + self.Left = self:Add("DButton") + self.Left:Dock(LEFT) + self.Left.Id = 1 + self.Left:SetText(tbl[self.Left.Id]) + self.Left:SetFont("Nexus.PingSystem.Settings.Boolean") + self.Left.Paint = function(pnl, w, h) + pnl:SetTextColor(self.Selected == pnl.Id and color_white or Color(183, 183, 183)) + + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(pnl:IsHovered() and PIS.Config.HighlightColor or Color(83, 83, 83)) + surface.DrawOutlinedRect(0, 0, w, h) + + if (self.Selected == pnl.Id) then + surface.SetDrawColor(PIS.Config.HighlightColor) + surface.DrawRect(0, h - 2, w, 2) + end + end + self.Left.DoClick = function(pnl) + self:RequestFocus() + + self:SetSelected(pnl.Id) + + surface.PlaySound("ping_system/accept.wav") + end + + self.Right = self:Add("DButton") + self.Right:Dock(FILL) + self.Right:DockMargin(8, 0, 0, 0) + self.Right.Id = 2 + self.Right:SetText(tbl[self.Right.Id]) + self.Right:SetFont("Nexus.PingSystem.Settings.Boolean") + self.Right.Paint = function(pnl, w, h) + pnl:SetTextColor(self.Selected == pnl.Id and color_white or Color(183, 183, 183)) + + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(pnl:IsHovered() and PIS.Config.HighlightColor or Color(83, 83, 83)) + surface.DrawOutlinedRect(0, 0, w, h) + + if (self.Selected == pnl.Id) then + surface.SetDrawColor(PIS.Config.HighlightColor) + surface.DrawRect(0, h - 2, w, 2) + end + end + self.Right.DoClick = function(pnl) + self:RequestFocus() + + self:SetSelected(pnl.Id) + + surface.PlaySound("ping_system/accept.wav") + end +end + +function PANEL:SetSelected(index) + self.Selected = index + + if (self.OnChange) then + self:OnChange(index) + end +end + +function PANEL:PerformLayout(w, h) + self.Left:SetWide(w / 2 - 4) +end + +vgui.Register("Nexus.PingSystem.Settings.Boolean", PANEL) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/elements/slider.lua b/lua/infl_cmenu/vgui/elements/slider.lua new file mode 100644 index 0000000..0252036 --- /dev/null +++ b/lua/infl_cmenu/vgui/elements/slider.lua @@ -0,0 +1,57 @@ +local PANEL = {} + +function PANEL:Init() + self.Frac = 0.5 +end + +function PANEL:OnMousePressed() + self:MouseCapture(true) + self.Depressed = true + + self:ChangeFraction() +end + +function PANEL:ChangeFraction() + local x, y = self:CursorPos() + local w = self:GetWide() + local frac = math.Clamp(x / w, 0, 1) + + if (frac != self.Frac) then + self:OnValueChanged(frac) + end + + self.Frac = frac +end + +function PANEL:OnValueChanged(frac) + +end + +function PANEL:OnCursorMoved() + if (!self.Depressed) then return end + + self:ChangeFraction() +end + +function PANEL:OnMouseReleased() + self:MouseCapture(false) + self.Depressed = false +end + +function PANEL:Paint(w, h) + surface.SetDrawColor(0, 0, 0, 150) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(138, 137, 138) + surface.DrawRect(0, 0, (w * self.Frac) - 4, h) + + surface.SetDrawColor(PIS.Config.HighlightColor) + surface.DrawRect(math.Clamp((w * self.Frac) - 4, 0, w), 0, 4, h) + + surface.SetDrawColor(self.Depressed and PIS.Config.HighlightColor or Color(83, 83, 83)) + for i = 0, self.Depressed and 1 or 0 do + surface.DrawOutlinedRect(i, i, w - (i * 2), h - (i * 2)) + end +end + +vgui.Register("Nexus.PingSystem.Slider", PANEL) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/elements/subtabs.lua b/lua/infl_cmenu/vgui/elements/subtabs.lua new file mode 100644 index 0000000..dd516ea --- /dev/null +++ b/lua/infl_cmenu/vgui/elements/subtabs.lua @@ -0,0 +1,107 @@ +local framework = Nexus:ClassManager("Framework") +local panels = framework:Class("Panels") + +local PANEL = {} + +surface.CreateFont("Nexus.PingSystem.Menu.SubTabs", { + font = "TT Lakes Medium", + size = 21 +}) + +function PANEL:Init() + self.Tabs = {} +end + +function PANEL:Select(id) + if (self.ActiveTab == id) then return end + + local btn = self.Tabs[self.ActiveTab] + if (IsValid(btn)) then + btn.TextColor = Color(180, 180, 180) + btn.BarColor = Color(180, 180, 180) + btn.BackgroundColor = Color(68, 68, 68, 200) + + local pnl = btn.Panel + if (IsValid(pnl)) then + pnl:SetVisible(false) + end + end + + self.ActiveTab = id + + local btn = self.Tabs[id] + if (IsValid(btn)) then + btn.TextColor = color_white + btn.BarColor = PIS.Config.HighlightColor + btn.BackgroundColor = Color(146, 36, 41, 200) + + local pnl = btn.Panel + if (IsValid(pnl)) then + pnl:SetVisible(true) + end + end + + if (self.OnTabChanged) then + self:OnTabChanged(id) + end +end + +function PANEL:AddTab(name, panelClass) + local button = panels:Call("Create", "DButton", self) + button:SetText("") + button.TextColor = Color(180, 180, 180) + button.BarColor = Color(180, 180, 180) + button.Paint = function(pnl, w, h) + local polygon = { + { x = 0, y = 0 }, + { x = w, y = 0 }, + { x = w + w * 0.084, y = h }, + { x = w * 0.084, y = h } + } + + DisableClipping(true) + draw.NoTexture() + surface.SetDrawColor(ColorAlpha(self.ActiveTab == pnl.Id and PIS.Config.HighlightTabColor or Color(180, 180, 180), self.ActiveTab == pnl.Id and 75 or 20)) + surface.DrawPoly(polygon) + + local polygon = { + { x = w * 0.082, y = h - 4 }, + { x = w + w * 0.084 - 1, y = h - 4 }, + { x = w + w * 0.084, y = h }, + { x = w * 0.082 + 1, y = h } + } + surface.SetDrawColor(pnl.BarColor) + surface.DrawPoly(polygon) + DisableClipping(false) + + draw.SimpleText(name, "Nexus.PingSystem.Menu.SubTabs", w / 2 + (w * 0.042), h / 2 - 2, pnl.TextColor, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + end + button.DoClick = function(pnl) + surface.PlaySound("ping_system/accept.wav") + + self:Select(pnl.Id) + end + + local panel = panels:Call("Create", panelClass or "Panel", self:GetParent()) + panel:Dock(FILL) + panel:DockMargin(0, 60, 0, 0) + panel:SetVisible(false) + + button.Panel = panel + + local id = table.insert(self.Tabs, button) + self.Tabs[id].Id = id +end + +function PANEL:PerformLayout(w, h) + local x = 52 + local width = 145 + for i, v in pairs(self.Tabs) do + v:SetSize(width, h) + v:SetPos(x, 0) + + x = x + width + 2 + end +end + +vgui.Register("Nexus.PingSystem.SubTabs", PANEL) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/elements/textentry.lua b/lua/infl_cmenu/vgui/elements/textentry.lua new file mode 100644 index 0000000..1d69cc4 --- /dev/null +++ b/lua/infl_cmenu/vgui/elements/textentry.lua @@ -0,0 +1,32 @@ +local PANEL = {} + +function PANEL:Init() + self.TextEntry = self:Add("DTextEntry") + self.TextEntry:Dock(FILL) + self.TextEntry:DockMargin(4, 4, 4, 4) + self.TextEntry:SetFont("Nexus.PingSystem.Settings.Option.Name") + self.TextEntry:SetDrawLanguageID(false) + self.TextEntry:SetNumeric(true) + self.TextEntry:SetUpdateOnType(true) + self.TextEntry.Paint = function(pnl, w, h) + local col = pnl:HasFocus() and color_white or Color(202, 202, 202) + + pnl:DrawTextEntryText(col, color_black, color_white) + end +end + +function PANEL:SetText(text) + self.TextEntry:SetText(text) +end + +function PANEL:Paint(w, h) + surface.SetDrawColor(0, 0, 0, 150) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(self.TextEntry:HasFocus() and PIS.Config.HighlightColor or Color(83, 83, 83)) + for i = 0, self.TextEntry:HasFocus() and 1 or 0 do + surface.DrawOutlinedRect(i, i, w - (i * 2), h - (i * 2)) + end +end + +vgui.Register("Nexus.PingSystem.TextEntry", PANEL) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/frame.lua b/lua/infl_cmenu/vgui/frame.lua new file mode 100644 index 0000000..f551ed7 --- /dev/null +++ b/lua/infl_cmenu/vgui/frame.lua @@ -0,0 +1,163 @@ +local framework = Nexus:ClassManager("Framework") +local _draw = framework:Class("Draw") +local anim = framework:Class("Animations") +local panels = framework:Class("Panels") +local testing = framework:Class("Testing") + +local PANEL = {} + +surface.CreateFont("Nexus.PingSystem.Menu.Tabs", { + font = "TT Lakes Medium", + size = 28 +}) + +local closeButton = Material("xenin/closebutton.png", "smooth") + +function PANEL:Select(id) + if (self.ActiveTab == id) then return end + + local btn = self.Tab.Tabs[self.ActiveTab] + if (IsValid(btn)) then + btn.TextColor = Color(180, 180, 180) + btn.BarColor = Color(180, 180, 180) + + local pnl = btn.Panel + if (IsValid(pnl)) then + pnl:SetVisible(false) + end + end + + self.ActiveTab = id + + local btn = self.Tab.Tabs[id] + if (IsValid(btn)) then + btn.TextColor = color_white + btn.BarColor = PIS.Config.HighlightColor + + local pnl = btn.Panel + if (IsValid(pnl)) then + pnl:SetVisible(true) + end + end + + LocalPlayer().PIS_LastSelectedTab = id +end + +function PANEL:Init() + self.Tab = panels:Call("Create", "Panel", self) + self.Tab:Dock(TOP) + self.Tab.Tabs = {} + self.Tab.AddTab = function(pnl, name, panelType) + local button = panels:Call("Create", "DButton", self.Tab) + button:SetText("") + button.TextColor = Color(180, 180, 180) + button.BarColor = Color(180, 180, 180) + button.Paint = function(pnl, w, h) + local polygon = { + { x = 0, y = 0 }, + { x = w, y = 0 }, + { x = w + w * 0.15, y = h }, + { x = w * 0.15, y = h } + } + DisableClipping(true) + draw.NoTexture() + surface.SetDrawColor(ColorAlpha(self.ActiveTab == pnl.Id and PIS.Config.HighlightTabColor or Color(180, 180, 180), self.ActiveTab == pnl.Id and 75 or 20)) + surface.DrawPoly(polygon) + + local polygon = { + { x = w * 0.14, y = h - 4 }, + { x = w + w * 0.15 - 1, y = h - 4 }, + { x = w + w * 0.15, y = h }, + { x = w * 0.14 + 1, y = h } + } + surface.SetDrawColor(pnl.BarColor) + surface.DrawPoly(polygon) + DisableClipping(false) + + draw.SimpleText(name, "Nexus.PingSystem.Menu.Tabs", w / 2 + (w * 0.15 / 2), h - 12, pnl.TextColor, TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM) + end + button.DoClick = function(pnl) + surface.PlaySound("ping_system/accept.wav") + + self:Select(pnl.Id) + end + + local id = table.insert(pnl.Tabs, button) + pnl.Tabs[id].Id = id + + local panel = panels:Call("Create", panelType or "DPanel", self) + panel:SetVisible(false) + + button.Panel = panel + pnl.Tabs[id].Panel = panel + end + self.Tab:AddTab("PLAYERS", "Nexus.PingSystem.Players") + self.Tab:AddTab("SETTINGS", "Nexus.PingSystem.Settings") + --self.Tab:AddTab("ADMIN", "Nexus.PingSystem.Admin") + self:Select(LocalPlayer().PIS_LastSelectedTab or 1) + + self.CloseButton = panels:Call("Create", "DButton", self.Tab) + self.CloseButton:Dock(RIGHT) + self.CloseButton:SetText("") + self.CloseButton.Paint = function(pnl, w, h) + local margin = 24 + + surface.SetDrawColor(color_white) + surface.SetMaterial(closeButton) + surface.DrawTexturedRect(w - (w - (margin * 2)) - margin, margin + 2, w - (margin * 2), h - (margin * 2)) + end + self.CloseButton.DoClick = function(pnl) + self:Close() + end +end + +function PANEL:Paint(w, h) + surface.SetDrawColor(PIS.Config.BackgroundColor) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(0, 0, 0, 150) + surface.DrawRect(0, 0, w, self.Tab:GetTall()) +end + +function PANEL:PerformLayout(w, h) + self.Tab:SetTall(64) + + local width = 160 + local x = 16 + local amt = table.Count(self.Tab.Tabs) + for i, v in pairs(self.Tab.Tabs) do + /* + local x + if (i == 1) then + x = w / 2 - width / 2 + elseif (i % 2 == 0) then + x = w / 2 + (width / 2 * math.floor(i / 2)) + 4 + elseif (i % 2 == 1) then + x = w / 2 - (width / 2 * math.floor(i / 2)) - width - 4 + end*/ + + v:SetPos(x, 0) + v:SetSize(width, self.Tab:GetTall()) + + x = x + v:GetWide() + 2 + + v.Panel:SetPos(0, v:GetTall()) + v.Panel:SetSize(w, h - v:GetTall()) + end +end + +function PANEL:Close() + self:Remove() +end + +vgui.Register("Nexus.PingSystem.Frame", PANEL, "EditablePanel") + +testing:Call("Add", "ping_frame", function() + local frame = panels:Call("Create", "Nexus.PingSystem.Frame") + frame:SetSize(1060 * 0.75, 628) + frame:Center() + frame:MakePopup() +end) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/players/players.lua b/lua/infl_cmenu/vgui/players/players.lua new file mode 100644 index 0000000..8629d26 --- /dev/null +++ b/lua/infl_cmenu/vgui/players/players.lua @@ -0,0 +1,27 @@ +local framework = Nexus:ClassManager("Framework") +local panels = framework:Class("Panels") + +local PANEL = {} + +function PANEL:Init() + self.Tabs = panels:Call("Create", "Nexus.PingSystem.SubTabs", self) + self.Tabs:AddTab("PINGS", "Nexus.PingSystem.Players.Pings") + self.Tabs:AddTab("COMMANDS", "Nexus.PingSystem.Players.Commands") + self.Tabs.OnTabChanged = function(pnl, id) + LocalPlayer().PIS_LastSelectedSubTabPlayers = id + end + self.Tabs:Select(LocalPlayer().PIS_LastSelectedSubTabPlayers or 1) +end + +function PANEL:Paint(w, h) + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, 60) +end + +function PANEL:PerformLayout(w, h) + self.Tabs:SetTall(36) + self.Tabs:SetPos(0, 12) + self.Tabs:SetWide(w) +end + +vgui.Register("Nexus.PingSystem.Players", PANEL) diff --git a/lua/infl_cmenu/vgui/players/tabs/players_commands.lua b/lua/infl_cmenu/vgui/players/tabs/players_commands.lua new file mode 100644 index 0000000..29552d5 --- /dev/null +++ b/lua/infl_cmenu/vgui/players/tabs/players_commands.lua @@ -0,0 +1,118 @@ +local framework = Nexus:ClassManager("Framework") +local _draw = framework:Class("Draw") + +local PANEL = {} + +surface.CreateFont("Nexus.PingSystem.Players.Buddies.Title", { + font = "Lato", + size = 24, + weight = 500 +}) + +surface.CreateFont("Nexus.PingSystem.Players.Buddies.Name", { + font = "Lato", + size = 28, + weight = 800 +}) + +surface.CreateFont("Nexus.PingSystem.Players.Buddies.Desc", { + font = "Lato", + size = 22, + weight = 500 +}) + +local muted = Material("ping_system/muted.png", "smooth") +local unmuted = Material("ping_system/unmuted.png", "smooth") + +function PANEL:Init() + self:DockPadding(16, 16, 16, 16) + + self.Scroll = self:Add("DScrollPanel") + self.Scroll:Dock(FILL) + self.Scroll:DockMargin(0, 0, 0, 0) + + self.Title = self.Scroll:Add("DLabel") + self.Title:Dock(TOP) + self.Title:DockMargin(0, 0, 0, 16) + self.Title:SetText("You can command these people") + self.Title:SetFont("Nexus.PingSystem.Players.Buddies.Title") + self.Title:SetTextColor(color_white) + self.Title:SizeToContents() + + self.Layout = self.Scroll:Add("DIconLayout") + self.Layout:Dock(FILL) + self.Layout:SetSpaceX(8) + self.Layout:SetSpaceY(8) + + local players = {} + for i, v in pairs(player.GetAll()) do + if (v == LocalPlayer()) then continue end + if (!PIS.Gamemode:GetCommandCondition()(LocalPlayer(), v)) then continue end + + table.insert(players, v) + end + + for i, v in pairs(players) do + local panel = self.Layout:Add("DButton") + panel:SetText("") + panel:SetTall(64) + panel.Paint = function(pnl, w, h) + local border = pnl:IsHovered() and 2 or 1 + local outer = { + { x = 0, y = 0 }, + { x = w, y = 0 }, + { x = w, y = h * 0.7 }, + { x = w - 16, y = h }, + { x = 0, y = h } + } + local inner = { + { x = border, y = border }, + { x = w - border, y = border }, + { x = w - border, y = h * 0.7 - border }, + { x = w - border - 16, y = h - border }, + { x = border, y = h - border } + } + + draw.NoTexture() + + surface.SetDrawColor(Color(0, 0, 0, 100)) + surface.DrawPoly(inner) + + _draw:Call("MaskExclude", function() + surface.SetDrawColor(color_white) + surface.DrawPoly(inner) + end, function() + surface.SetDrawColor(pnl:IsHovered() and PIS.Config.HighlightColor or Color(83, 83, 83)) + surface.DrawPoly(outer) + end) + + local x = 8 + pnl.Avatar:GetWide() + 8 + + draw.SimpleText(v:Nick(), "Nexus.PingSystem.Players.Buddies.Name", x, h / 2 + 3, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM) + draw.SimpleText(PIS.Gamemode:GetSubtitleDisplay()(v), "Nexus.PingSystem.Players.Buddies.Desc", x, h / 2, Color(224, 224, 222), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + end + panel.OnCursorEntered = function(pnl) + surface.PlaySound("ping_system/hover.wav") + end + + panel.Avatar = panel:Add("AvatarImage") + panel.Avatar:SetPlayer(v, 128) + panel.Avatar:Dock(LEFT) + panel.Avatar:DockMargin(8, 8, 8, 8) + panel.Avatar:SetWide(48) + end +end + +function PANEL:PerformLayout(w, h) + for i, v in pairs(self.Layout:GetChildren()) do + v:SetWide(self.Layout:GetWide() / 2 - 4) + end +end + +function PANEL:Paint(w, h) + if (#self.Layout:GetChildren() == 0) then + _draw:Call("ShadowText", "You can't command anyone :(", "Nexus.PingSystem.Players.Buddies.Name", w / 2, 72, Color(212, 212, 218), TEXT_ALIGN_CENTER) + end +end + +vgui.Register("Nexus.PingSystem.Players.Commands", PANEL) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/players/tabs/players_pings.lua b/lua/infl_cmenu/vgui/players/tabs/players_pings.lua new file mode 100644 index 0000000..d35ca51 --- /dev/null +++ b/lua/infl_cmenu/vgui/players/tabs/players_pings.lua @@ -0,0 +1,144 @@ +local framework = Nexus:ClassManager("Framework") +local _draw = framework:Class("Draw") + +local PANEL = {} + +surface.CreateFont("Nexus.PingSystem.Players.Buddies.Title", { + font = "Lato", + size = 24, + weight = 500 +}) + +surface.CreateFont("Nexus.PingSystem.Players.Buddies.Name", { + font = "Lato", + size = 28, + weight = 800 +}) + +surface.CreateFont("Nexus.PingSystem.Players.Buddies.Desc", { + font = "Lato", + size = 22, + weight = 500 +}) + +local muted = Material("ping_system/muted.png", "smooth") +local unmuted = Material("ping_system/unmuted.png", "smooth") + +function PANEL:Init() + self:DockPadding(16, 16, 16, 16) + + self.Title = self:Add("DLabel") + self.Title:Dock(TOP) + self.Title:SetText("People that can see your pings, and the people's pings you can see") + self.Title:SetFont("Nexus.PingSystem.Players.Buddies.Title") + self.Title:SetTextColor(color_white) + self.Title:SizeToContents() + + self.Scroll = self:Add("DScrollPanel") + self.Scroll:Dock(FILL) + self.Scroll:DockMargin(0, 16, 0, 0) + + self.Layout = self.Scroll:Add("DIconLayout") + self.Layout:Dock(FILL) + self.Layout:SetSpaceX(8) + self.Layout:SetSpaceY(8) + + local players = {} + for i, v in pairs(player.GetAll()) do + if (v == LocalPlayer()) then continue end + if (!PIS.Gamemode:GetViewCondition()(LocalPlayer(), v)) then continue end + + table.insert(players, v) + end + + for i, v in pairs(players) do + local panel = self.Layout:Add("DButton") + panel:SetText("") + panel:SetTall(64) + panel.Paint = function(pnl, w, h) + local border = (pnl:IsHovered() or pnl.Muted:IsHovered()) and 2 or 1 + local outer = { + { x = 0, y = 0 }, + { x = w, y = 0 }, + { x = w, y = h * 0.7 }, + { x = w - 16, y = h }, + { x = 0, y = h } + } + local inner = { + { x = border, y = border }, + { x = w - border, y = border }, + { x = w - border, y = h * 0.7 - border }, + { x = w - border - 16, y = h - border }, + { x = border, y = h - border } + } + + draw.NoTexture() + + surface.SetDrawColor(Color(0, 0, 0, 100)) + surface.DrawPoly(inner) + + _draw:Call("MaskExclude", function() + surface.SetDrawColor(color_white) + surface.DrawPoly(inner) + end, function() + surface.SetDrawColor((pnl:IsHovered() or pnl.Muted:IsHovered()) and PIS.Config.HighlightColor or Color(83, 83, 83)) + surface.DrawPoly(outer) + end) + + local x = 8 + pnl.Avatar:GetWide() + 8 + + draw.SimpleText(v:Nick(), "Nexus.PingSystem.Players.Buddies.Name", x, h / 2 + 3, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM) + draw.SimpleText(PIS.Gamemode:GetSubtitleDisplay()(v), "Nexus.PingSystem.Players.Buddies.Desc", x, h / 2, Color(224, 224, 222), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP) + end + panel.OnCursorEntered = function(pnl) + surface.PlaySound("ping_system/hover.wav") + end + panel.DoClick = function(pnl) + surface.PlaySound("ping_system/accept.wav") + + pnl.Muted:DoClick() + end + + panel.Avatar = panel:Add("AvatarImage") + panel.Avatar:SetPlayer(v, 128) + panel.Avatar:Dock(LEFT) + panel.Avatar:DockMargin(8, 8, 8, 8) + panel.Avatar:SetWide(48) + + panel.Muted = panel:Add("DButton") + panel.Muted:SetMouseInputEnabled(false) + panel.Muted:SetText("") + panel.Muted.Muted = false + panel.Muted.Paint = function(pnl, w, h) + surface.SetDrawColor(panel:IsHovered() and color_white or Color(183, 183, 183)) + surface.SetMaterial(pnl.Muted and muted or unmuted) + surface.DrawTexturedRect(0, 0, w, h) + end + panel.Muted.DoClick = function(pnl) + pnl.Muted = !pnl.Muted + + PIS:SetMuted(LocalPlayer(), v, pnl.Muted) + end + + panel.PerformLayout = function(pnl, w, h) + panel.Muted:AlignRight(20) + panel.Muted:AlignTop(15) + panel.Muted:SetTall(h - 30) + panel.Muted:SetWide(panel.Muted:GetTall()) + end + end +end + +function PANEL:PerformLayout(w, h) + for i, v in pairs(self.Layout:GetChildren()) do + v:SetWide(self.Layout:GetWide() / 2 - 4) + end +end + +function PANEL:Paint(w, h) + if (#self.Layout:GetChildren() == 0) then + _draw:Call("ShadowText", "Nobody can see your pings :(", "Nexus.PingSystem.Players.Buddies.Name", w / 2, 72, Color(212, 212, 218), TEXT_ALIGN_CENTER) + end +end + +vgui.Register("Nexus.PingSystem.Players.Pings", PANEL) diff --git a/lua/infl_cmenu/vgui/settings/elements/settings_combobox.lua b/lua/infl_cmenu/vgui/settings/elements/settings_combobox.lua new file mode 100644 index 0000000..8e4fb17 --- /dev/null +++ b/lua/infl_cmenu/vgui/settings/elements/settings_combobox.lua @@ -0,0 +1,123 @@ +local PANEL = {} + +surface.CreateFont("Nexus.PingSystem.Settings.Option.Arrow", { + font = "TT Lakes Medium", + size = 40 +}) + +surface.CreateFont("Nexus.PingSystem.Settings.Option.Combobox", { + font = "TT Lakes Medium", + size = 22, + weight = 500 +}) + +local arrow = Material("ping_system/arrow.png", "smooth") + +function PANEL:Init() + self.LeftArrow = self:Add("DButton") + self.LeftArrow:Dock(LEFT) + self.LeftArrow:SetText("") + self.LeftArrow:SetContentAlignment(2) + self.LeftArrow:SetFont("Nexus.PingSystem.Settings.Option.Arrow") + self.LeftArrow.Paint = function(pnl, w, h) + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(pnl:IsHovered() and PIS.Config.HighlightColor or Color(83, 83, 83)) + for i = 0, pnl:IsHovered() and 1 or 0 do + surface.DrawOutlinedRect(i, i, w - (i * 2), h - (i * 2)) + end + + local margin = 10 + local size = w - (margin * 2) + local sizeW = size * 0.7 + local marginX = w / 2 - sizeW / 2 + surface.SetMaterial(arrow) + surface.SetDrawColor(pnl:IsHovered() and color_white or Color(212, 212, 212)) + surface.DrawTexturedRect(marginX, margin, sizeW, size) + end + self.LeftArrow.DoClick = function(pnl) + self:RequestFocus() + + self:SetSelected(math.Clamp(self.Selected - 1, 1, #self.Options)) + + surface.PlaySound("ping_system/accept.wav") + end + + self.RightArrow = self:Add("DButton") + self.RightArrow:Dock(RIGHT) + self.RightArrow:SetText("") + self.RightArrow:SetContentAlignment(2) + self.RightArrow:SetFont("Nexus.PingSystem.Settings.Option.Arrow") + self.RightArrow.Paint = function(pnl, w, h) + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(pnl:IsHovered() and PIS.Config.HighlightColor or Color(83, 83, 83)) + for i = 0, pnl:IsHovered() and 1 or 0 do + surface.DrawOutlinedRect(i, i, w - (i * 2), h - (i * 2)) + end + + local margin = 10 + local size = w - (margin * 2) + local sizeW = size * 0.7 + local marginX = w / 2 - sizeW / 2 + surface.SetMaterial(arrow) + surface.SetDrawColor(pnl:IsHovered() and color_white or Color(212, 212, 212)) + surface.DrawTexturedRectRotated(marginX + sizeW / 2, margin + size / 2, sizeW, size, 180) + end + self.RightArrow.DoClick = function(pnl) + self:RequestFocus() + + self:SetSelected(math.Clamp(self.Selected + 1, 1, #self.Options)) + + surface.PlaySound("ping_system/accept.wav") + end + + self.Options = {} + + self.Box = self:Add("DPanel") + self.Box:Dock(FILL) + self.Box:DockMargin(8, 0, 8, 0) + self.Box.Paint = function(pnl, w, h) + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(83, 83, 83) + surface.DrawOutlinedRect(0, 0, w, h) + + local x = 1 + local width = w / #self.Options - (4 / #self.Options) - 2 + for i = 0, #self.Options - 1 do + surface.SetDrawColor(self.Selected == (i + 1) and PIS.Config.HighlightColor or Color(222, 222, 222)) + surface.DrawRect(x, h - 3, width, 2) + + x = x + width + 4 + end + + local options = self.Options[self.Selected] + local name = istable(options) and options[1] or options + draw.SimpleText(name, "Nexus.PingSystem.Settings.Option.Combobox", w / 2, h / 2 - 1, Color(222, 222, 222), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) + end + + self.Selected = 1 +end + +function PANEL:SetOptions(tbl) + self.Options = tbl +end + +function PANEL:SetSelected(index) + self.Selected = index + + if (self.OnChange) then + self:OnChange(index) + end +end + +function PANEL:PerformLayout(w, h) + self.LeftArrow:SetWide(self.LeftArrow:GetTall()) + self.RightArrow:SetWide(self.RightArrow:GetTall()) +end + +vgui.Register("Nexus.PingSystem.Settings.Combobox", PANEL) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/settings/elements/settings_key.lua b/lua/infl_cmenu/vgui/settings/elements/settings_key.lua new file mode 100644 index 0000000..88d32ba --- /dev/null +++ b/lua/infl_cmenu/vgui/settings/elements/settings_key.lua @@ -0,0 +1,60 @@ +local PANEL = {} + +function PANEL:Paint(w, h) + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + local num = self.Active and 2 or self:IsHovered() and 1 or 0 + surface.SetDrawColor((self.Active or self:IsHovered()) and PIS.Config.HighlightColor or Color(83, 83, 83)) + for i = 0, num do + surface.DrawOutlinedRect(i, i, w - (i * 2), h - (i * 2)) + end + + local code = PIS:GetKeyName(self.Key) + draw.SimpleText(code, "Nexus.PingSystem.Settings.Option.Combobox", w / 2, h / 2, Color(222, 222, 222), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER) +end + +function PANEL:OnFocusChanged(gained) + if (!gained and self.Active) then + self.Active = nil + end +end + +function PANEL:OnChange() + +end + +function PANEL:OnKeyCodeReleased(keyCode) + if (!self.Active) then return end + + if (keyCode != KEY_ESCAPE) then + self.Key = keyCode + + self:OnChange(self.Key) + end + + self:KillFocus() + self.Active = nil +end + +function PANEL:OnMouseReleased(mouseCode) + if (mouseCode >= MOUSE_MIDDLE) then + -- Not left or right + + self.Key = mouseCode + + self:KillFocus() + self.Active = nil + + self:OnChange(self.Key) + + return + end + + surface.PlaySound("ping_system/accept.wav") + self.Active = true + + self:RequestFocus() +end + +vgui.Register("Nexus.PingSystem.Settings.Key", PANEL) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/settings/elements/settings_slider.lua b/lua/infl_cmenu/vgui/settings/elements/settings_slider.lua new file mode 100644 index 0000000..209cf24 --- /dev/null +++ b/lua/infl_cmenu/vgui/settings/elements/settings_slider.lua @@ -0,0 +1,55 @@ +local PANEL = {} + +AccessorFunc(PANEL, "m_min", "Min") +AccessorFunc(PANEL, "m_max", "Max") + +function PANEL:Init() + self:SetMin(0) + self:SetMax(100) + + self.Slider = self:Add("Nexus.PingSystem.Slider") + self.Slider:Dock(FILL) + self.Slider:DockMargin(0, 0, 12, 0) + self.Slider.OnValueChanged = function(pnl, frac) + self:OnValueChanged(frac) + end + + self.TextEntry = self:Add("Nexus.PingSystem.TextEntry") + self.TextEntry:Dock(RIGHT) + self.TextEntry:SetWide(54) + self.TextEntry.TextEntry.OnValueChange = function(pnl, text) + text = tonumber(text) + text = text or 0 + + text = math.Clamp(text, self:GetMin(), self:GetMax()) + self:OnValueChanged((text - self:GetMin()) / (self:GetMax() - self:GetMin()), true) + end + self.TextEntry.TextEntry.OnFocusChanged = function(pnl, gained) + if (!gained) then + local text = tonumber(pnl:GetText()) + text = text or 0 + + text = math.Clamp(text, self:GetMin(), self:GetMax()) + pnl:SetText(text) + end + end + + self:OnValueChanged(0.5) +end + +function PANEL:OnValueChanged(frac, ignoreText) + local min = self:GetMin() + local max = self:GetMax() + local num = math.Round(((1 - frac) * min) + (frac * max), max >= 10 and 0 or 2) + + if (!ignoreText) then + self.TextEntry:SetText(num) + end + self.Slider.Frac = frac + + if (self.OnChange) then + self:OnChange(num) + end +end + +vgui.Register("Nexus.PingSystem.Settings.Slider", PANEL) \ No newline at end of file diff --git a/lua/infl_cmenu/vgui/settings/settings.lua b/lua/infl_cmenu/vgui/settings/settings.lua new file mode 100644 index 0000000..0424651 --- /dev/null +++ b/lua/infl_cmenu/vgui/settings/settings.lua @@ -0,0 +1,174 @@ +local framework = Nexus:ClassManager("Framework") +local panels = framework:Class("Panels") + +local PANEL = {} + +function PANEL:Init() + self.Tabs = panels:Call("Create", "Nexus.PingSystem.SubTabs", self) + self.Tabs:AddTab("PING", "Nexus.PingSystem.Settings.Ping") + self.Tabs:AddTab("KEYS", "Nexus.PingSystem.Settings.Keys") + self.Tabs:AddTab("WHEEL UI", "Nexus.PingSystem.Settings.Wheel") + self.Tabs.OnTabChanged = function(pnl, id) + LocalPlayer().PIS_LastSelectedSubTabSettings = id + end + self.Tabs:Select(LocalPlayer().PIS_LastSelectedSubTabSettings or 1) +end + +function PANEL:Paint(w, h) + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, 60) +end + +function PANEL:PerformLayout(w, h) + self.Tabs:SetTall(36) + self.Tabs:SetPos(0, 12) + self.Tabs:SetWide(w) +end + +vgui.Register("Nexus.PingSystem.Settings", PANEL) + +PSI_SETTINGS_SLIDER = 0 +PSI_SETTINGS_COMBOBOX = 1 +PSI_SETTINGS_KEY = 2 + +PIS.Settings = { + { Name = "Ping sound", + Input = PSI_SETTINGS_COMBOBOX, + Default = function(settings) return settings.PingSound or 1 end, + Options = { "All pings", "Targeted pings", "Disabled"}, + Desc = "Should other peoples pings give off sound?\n\n- All pings means every single ping will give off a sound\n\n- Targeted pings means only pings directly targeted at you will give off sounds\n\n- Disabled means disabled", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "PingSound", value) + end + }, + { Name = "Ping pulsating", + Input = PSI_SETTINGS_COMBOBOX, + Default = function(settings) return settings.PingPulsating or 2 end, + Options = { "All pings", "Targeted pings", "Disabled" }, + Desc = "Should pings pulsate?\n\n- All pings means every single ping will pulsate constantly or until confirmed\n\n- Targeted pings means only pings directly targeted at you will pulsate\n\n- Disabled means disabled", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "PingPulsating", value) + end + }, + { Name = "Ping offscreen 2D render", + Input = PSI_SETTINGS_COMBOBOX, + Default = function(settings) return settings.PingOffscreen or 1 end, + Options = { "All pings", "Targeted pings", "Disabled" }, + Desc = "Should that you can't see in the 3D world be rendered at the edge of your screen?\n\n- All pings means every single ping will be rendered\n\n- Targeted pings means only pings directly targeted at you will be rendered\n\n- Disabled means disabled", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "PingOffscreen", value) + end, + TitleReplacement = "Offscreen Rendering" + }, + { Name = "Ping icon set", + Input = PSI_SETTINGS_COMBOBOX, + Default = function(settings) return settings.PingIconSet or 1 end, + Options = function() + local tbl = {} + + for i, v in ipairs(PIS.Config.PingSets) do + tbl[i] = v.name + end + + return tbl + end, + Desc = "Changes the icons you see according to the theme", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "PingIconSet", value) + end + }, + { Name = "Ping overhead", + Input = PSI_SETTINGS_COMBOBOX, + Default = function(settings) return settings.PingOverhead or 1 end, + Options = { "Avatar", "Square" }, + Desc = "Should the avatar of the player be displayed above the ping if it's a command ping? Or should it be a rotated square", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "PingOverhead", value) + end + }, + { Name = "Ping icon size", + Input = PSI_SETTINGS_SLIDER, + Default = function(settings) return (settings.Scale or 1) * 128 end, + Min = 64, + Max = 256, + Desc = "Changes the size of the pings in 3D.\n\nDefault is 128, and is technically 100% size.\n\nThis is independent of ping detection, and therefore having a really big icon, but low ping detection might make it not accurate", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "Scale", value / 128) + end + }, + { Name = "Ping avatar vertices", + Input = PSI_SETTINGS_SLIDER, + Default = function(settings) return settings.PingAvatarVertices end, + Min = 8, + Max = 90, + Desc = "Changes the size of the pings in 3D.\n\nDefault is 128, and is technically 100% size.\n\nThis is independent of ping detection, and therefore having a really big icon, but low ping detection might make it not accurate", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "PingAvatarVertices", value) + end + }, + { Name = "Ping detection size", + Input = PSI_SETTINGS_SLIDER, + Default = function(settings) return (settings.DetectionScale or 1) * 128 end, + Min = 64, + Max = 256, + Desc = "This determines if you are looking at a ping.\n\nDefault is 100", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "DetectionScale", value / 128) + end + } +} + +PIS.SettingsKeys = { + { + Name = "Wheel key hold time", + Input = PSI_SETTINGS_SLIDER, + Default = function(settings) return settings.WheelDelay or 0.1 end, + Min = 0, + Max = 1, + Desc = "How long should you hold the wheel key in seconds for the wheel menu to open?\n\nDefault is 0.1", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "WheelDelay", value) + end + }, + { + Name = "Wheel key", + Input = PSI_SETTINGS_KEY, + Default = function(settings) return settings.WheelKey or MOUSE_MIDDLE end, + Desc = "What key should you hold to open the wheel menu?\n\nDefault is middle mouse button (scroll wheel press)", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "WheelKey", value) + end + }, + { + Name = "Interaction key", + Input = PSI_SETTINGS_KEY, + Default = function(settings) return settings.InteractionKey or KEY_F end, + Desc = "What key should you use to interact with pings?\n\nDeafult is F", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "InteractionKey", value) + end + }, +} + +PIS.SettingsWheel = { + { Name = "Wheel blur", Input = PSI_SETTINGS_COMBOBOX, Default = function(settings) return settings.WheelBlur or 1 end, Options = { "Enabled", "Disabled" }, + Desc = "Should the wheel be blurred? Disabling this might increase performance somewhat for users with a low-end CPU\n\nDefault is enabled", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "WheelBlur", value) + end + }, + { Name = "Wheel UI scale", Input = PSI_SETTINGS_SLIDER, Default = function(settings) return (settings.WheelScale or 1) * 100 end, Min = 20, Max = 300, + Desc = "Changes the UI to be bigger or smaller. This is listed in percentage, i.e. 100 = 100%\n\nDefault is 100", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "WheelScale", value / 100) + end + }, + { Name = "Wheel monochrome", Input = PSI_SETTINGS_COMBOBOX, Default = function(settings) return settings.WheelMonochrome or 1 end, Options = function() + return PIS.Config.WheelColors + end, + Desc = "Should the wheel's ping colors be one color?\nThis might be helpful for people that are colorblind and can't see specific colors very well\n\nDefault is disabled", + OnChange = function(self, value) + PIS:SetSetting(LocalPlayer(), "WheelMonochrome", value) + end + }, +} diff --git a/lua/infl_cmenu/vgui/settings/tabs/settings_keys.lua b/lua/infl_cmenu/vgui/settings/tabs/settings_keys.lua new file mode 100644 index 0000000..025dd85 --- /dev/null +++ b/lua/infl_cmenu/vgui/settings/tabs/settings_keys.lua @@ -0,0 +1,129 @@ +local PANEL = {} + +function PANEL:SetDescription(title, desc) + self.Explain.Title:SetText(title) + self.Explain.Title:SizeToContentsY() + + self.Explain.Desc:SetText(desc) +end + +function PANEL:OnCursorEntered() + self:SetDescription("", "") +end + +function PANEL:Init() + self:DockPadding(16, 16, 16, 16) + + self.Explain = self:Add("DPanel") + self.Explain:Dock(RIGHT) + self.Explain:DockMargin(0, 0, 0, 0) + self.Explain.Paint = function(pnl, w, h) + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(83, 83, 83) + surface.DrawOutlinedRect(0, 0, w, h) + end + self.Explain:DockPadding(8, 8, 8, 8) + + self.Explain.Title = self.Explain:Add("DLabel") + self.Explain.Title:Dock(TOP) + self.Explain.Title:SetFont("Nexus.PingSystem.Settings.Desc.Title") + self.Explain.Title:SetTextColor(color_white) + + self.Explain.Desc = self.Explain:Add("DLabel") + self.Explain.Desc:Dock(TOP) + self.Explain.Desc:SetFont("Nexus.PingSystem.Settings.Desc.Desc") + self.Explain.Desc:SetTextColor(Color(212, 212, 212)) + self.Explain.Desc:SetMultiline(true) + self.Explain.Desc:SetWrap(true) + self.Explain.Desc:SetContentAlignment(7) + + self.Explain.PerformLayout = function(pnl, w, h) + self.Explain.Desc:SetPos(8, 8 + self.Explain.Title:GetTall()) + self.Explain.Desc:SetSize(w - 16, h) + end + + self:SetDescription("", "") + + self.Scroll = self:Add("DScrollPanel") + self.Scroll:Dock(FILL) + self.Scroll:DockMargin(0, 0, 16, 0) + self.Scroll.OnCursorEntered = function(pnl, w, h) + self:SetDescription("", "") + end + + for i, v in ipairs(PIS.SettingsKeys) do + local panel = self.Scroll:Add("DPanel") + panel:Dock(TOP) + panel:DockMargin(0, 0, 0, 8) + panel:SetTall(52) + panel.Paint = function(pnl, w, h) + local hovered = pnl:IsHovered() + if (!hovered) then + local function recursiveCheck(panel) + for i, v in pairs(panel:GetChildren()) do + if (v:IsHovered()) then + hovered = true + + break + else + recursiveCheck(v) + end + end + end + + recursiveCheck(pnl) + end + + if (pnl.hovered != hovered and hovered) then + surface.PlaySound("ping_system/hover.wav") + end + + pnl.hovered = hovered + + surface.SetDrawColor(0, 0, 0, hovered and 160 or 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(pnl.hovered and PIS.Config.HighlightColor or Color(83, 83, 83)) + surface.DrawOutlinedRect(0, 0, w, h) + + draw.SimpleText(v.Name, "Nexus.PingSystem.Settings.Option.Name", 12, h / 2, hovered and color_white or Color(183, 183, 183), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + end + + local options = v.Options and isfunction(v.Options) and v.Options() or v.Options + local optionsLen = options and #options or 0 + panel.Input = panel:Add( + v.Input == PSI_SETTINGS_SLIDER and "Nexus.PingSystem.Settings.Slider" + or (v.Input == PSI_SETTINGS_COMBOBOX and optionsLen != 2) and "Nexus.PingSystem.Settings.Combobox" + or v.Input == PSI_SETTINGS_COMBOBOX and "Nexus.PingSystem.Settings.Boolean" + or v.Input == PSI_SETTINGS_KEY and "Nexus.PingSystem.Settings.Key") + panel.Input:Dock(RIGHT) + panel.Input:DockMargin(8, 8, 8, 8) + panel.Input:SetWide(238) + + local default = isfunction(v.Default) and v.Default(PIS:GetSettings(LocalPlayer())) or 0 + if (v.Input == PSI_SETTINGS_SLIDER) then + panel.Input:SetMin(v.Min) + panel.Input:SetMax(v.Max) + panel.Input:OnValueChanged((default - v.Min) / (v.Max - v.Min)) + elseif (v.Input == PSI_SETTINGS_COMBOBOX) then + panel.Input:SetOptions(isfunction(v.Options) and v.Options() or v.Options) + panel.Input:SetSelected(default) + elseif (v.Input == PSI_SETTINGS_KEY) then + panel.Input.Key = default + end + + panel.Input.OnChange = v.OnChange + + panel.OnCursorEntered = function(pnl) + self:SetDescription(v.TitleReplacement or v.Name, v.Desc or "") + end + end +end + +function PANEL:PerformLayout(w, h) + self.Explain:SetWide(240) +end + +vgui.Register("Nexus.PingSystem.Settings.Keys", PANEL) diff --git a/lua/infl_cmenu/vgui/settings/tabs/settings_ping.lua b/lua/infl_cmenu/vgui/settings/tabs/settings_ping.lua new file mode 100644 index 0000000..88aaa94 --- /dev/null +++ b/lua/infl_cmenu/vgui/settings/tabs/settings_ping.lua @@ -0,0 +1,145 @@ +local PANEL = {} + +surface.CreateFont("Nexus.PingSystem.Settings.Option.Name", { + font = "TT Lakes Medium", + size = 24 +}) + +surface.CreateFont("Nexus.PingSystem.Settings.Desc.Title", { + font = "TT Lakes Medium", + size = 26, + weight = 800 +}) + +surface.CreateFont("Nexus.PingSystem.Settings.Desc.Desc", { + font = "TT Lakes Medium", + size = 20 +}) + +function PANEL:SetDescription(title, desc) + self.Explain.Title:SetText(title) + self.Explain.Title:SizeToContentsY() + + self.Explain.Desc:SetText(desc) +end + +function PANEL:OnCursorEntered() + self:SetDescription("", "") +end + +function PANEL:Init() + self:DockPadding(16, 16, 16, 16) + + self.Explain = self:Add("DPanel") + self.Explain:Dock(RIGHT) + self.Explain:DockMargin(0, 0, 0, 0) + self.Explain.Paint = function(pnl, w, h) + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(83, 83, 83) + surface.DrawOutlinedRect(0, 0, w, h) + end + self.Explain:DockPadding(8, 8, 8, 8) + + self.Explain.Title = self.Explain:Add("DLabel") + self.Explain.Title:Dock(TOP) + self.Explain.Title:SetFont("Nexus.PingSystem.Settings.Desc.Title") + self.Explain.Title:SetTextColor(color_white) + + self.Explain.Desc = self.Explain:Add("DLabel") + self.Explain.Desc:Dock(TOP) + self.Explain.Desc:SetFont("Nexus.PingSystem.Settings.Desc.Desc") + self.Explain.Desc:SetTextColor(Color(212, 212, 212)) + self.Explain.Desc:SetMultiline(true) + self.Explain.Desc:SetWrap(true) + self.Explain.Desc:SetContentAlignment(7) + + self.Explain.PerformLayout = function(pnl, w, h) + self.Explain.Desc:SetPos(8, 8 + self.Explain.Title:GetTall()) + self.Explain.Desc:SetSize(w - 16, h) + end + + self:SetDescription("", "") + + self.Scroll = self:Add("DScrollPanel") + self.Scroll:Dock(FILL) + self.Scroll:DockMargin(0, 0, 16, 0) + self.Scroll.OnCursorEntered = function(pnl, w, h) + self:SetDescription("", "") + end + + for i, v in ipairs(PIS.Settings) do + local panel = self.Scroll:Add("DPanel") + panel:Dock(TOP) + panel:DockMargin(0, 0, 0, 8) + panel:SetTall(52) + panel.Paint = function(pnl, w, h) + local hovered = pnl:IsHovered() + if (!hovered) then + local function recursiveCheck(panel) + for i, v in pairs(panel:GetChildren()) do + if (v:IsHovered()) then + hovered = true + + break + else + recursiveCheck(v) + end + end + end + + recursiveCheck(pnl) + end + + if (pnl.hovered != hovered and hovered) then + surface.PlaySound("ping_system/hover.wav") + end + + pnl.hovered = hovered + + surface.SetDrawColor(0, 0, 0, hovered and 160 or 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(pnl.hovered and PIS.Config.HighlightColor or Color(83, 83, 83)) + surface.DrawOutlinedRect(0, 0, w, h) + + draw.SimpleText(v.Name, "Nexus.PingSystem.Settings.Option.Name", 12, h / 2, hovered and color_white or Color(183, 183, 183), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + end + + local options = v.Options and isfunction(v.Options) and v.Options() or v.Options + local optionsLen = options and #options or 0 + panel.Input = panel:Add( + v.Input == PSI_SETTINGS_SLIDER and "Nexus.PingSystem.Settings.Slider" + or (v.Input == PSI_SETTINGS_COMBOBOX and optionsLen != 2) and "Nexus.PingSystem.Settings.Combobox" + or v.Input == PSI_SETTINGS_COMBOBOX and "Nexus.PingSystem.Settings.Boolean" + or v.Input == PSI_SETTINGS_KEY and "Nexus.PingSystem.Settings.Key") + panel.Input:Dock(RIGHT) + panel.Input:DockMargin(8, 8, 8, 8) + panel.Input:SetWide(238) + + local default = isfunction(v.Default) and v.Default(PIS:GetSettings(LocalPlayer())) or 0 + if (v.Input == PSI_SETTINGS_SLIDER) then + panel.Input:SetMin(v.Min) + panel.Input:SetMax(v.Max) + panel.Input:OnValueChanged((default - v.Min) / (v.Max - v.Min)) + elseif (v.Input == PSI_SETTINGS_COMBOBOX) then + panel.Input:SetOptions(isfunction(v.Options) and v.Options() or v.Options) + panel.Input:SetSelected(default) + elseif (v.Input == PSI_SETTINGS_KEY) then + panel.Input.Key = default + end + + panel.Input.OnChange = v.OnChange + + panel.OnCursorEntered = function(pnl) + self:SetDescription(v.TitleReplacement or v.Name, v.Desc or "") + end + end +end + +function PANEL:PerformLayout(w, h) + self.Explain:SetWide(240) +end + +vgui.Register("Nexus.PingSystem.Settings.Ping", PANEL) diff --git a/lua/infl_cmenu/vgui/settings/tabs/settings_wheel.lua b/lua/infl_cmenu/vgui/settings/tabs/settings_wheel.lua new file mode 100644 index 0000000..a729534 --- /dev/null +++ b/lua/infl_cmenu/vgui/settings/tabs/settings_wheel.lua @@ -0,0 +1,129 @@ +local PANEL = {} + +function PANEL:SetDescription(title, desc) + self.Explain.Title:SetText(title) + self.Explain.Title:SizeToContentsY() + + self.Explain.Desc:SetText(desc) +end + +function PANEL:OnCursorEntered() + self:SetDescription("", "") +end + +function PANEL:Init() + self:DockPadding(16, 16, 16, 16) + + self.Explain = self:Add("DPanel") + self.Explain:Dock(RIGHT) + self.Explain:DockMargin(0, 0, 0, 0) + self.Explain.Paint = function(pnl, w, h) + surface.SetDrawColor(0, 0, 0, 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(83, 83, 83) + surface.DrawOutlinedRect(0, 0, w, h) + end + self.Explain:DockPadding(8, 8, 8, 8) + + self.Explain.Title = self.Explain:Add("DLabel") + self.Explain.Title:Dock(TOP) + self.Explain.Title:SetFont("Nexus.PingSystem.Settings.Desc.Title") + self.Explain.Title:SetTextColor(color_white) + + self.Explain.Desc = self.Explain:Add("DLabel") + self.Explain.Desc:Dock(TOP) + self.Explain.Desc:SetFont("Nexus.PingSystem.Settings.Desc.Desc") + self.Explain.Desc:SetTextColor(Color(212, 212, 212)) + self.Explain.Desc:SetMultiline(true) + self.Explain.Desc:SetWrap(true) + self.Explain.Desc:SetContentAlignment(7) + + self.Explain.PerformLayout = function(pnl, w, h) + self.Explain.Desc:SetPos(8, 8 + self.Explain.Title:GetTall()) + self.Explain.Desc:SetSize(w - 16, h) + end + + self:SetDescription("", "") + + self.Scroll = self:Add("DScrollPanel") + self.Scroll:Dock(FILL) + self.Scroll:DockMargin(0, 0, 16, 0) + self.Scroll.OnCursorEntered = function(pnl, w, h) + self:SetDescription("", "") + end + + for i, v in ipairs(PIS.SettingsWheel) do + local panel = self.Scroll:Add("DPanel") + panel:Dock(TOP) + panel:DockMargin(0, 0, 0, 8) + panel:SetTall(52) + panel.Paint = function(pnl, w, h) + local hovered = pnl:IsHovered() + if (!hovered) then + local function recursiveCheck(panel) + for i, v in pairs(panel:GetChildren()) do + if (v:IsHovered()) then + hovered = true + + break + else + recursiveCheck(v) + end + end + end + + recursiveCheck(pnl) + end + + if (pnl.hovered != hovered and hovered) then + surface.PlaySound("ping_system/hover.wav") + end + + pnl.hovered = hovered + + surface.SetDrawColor(0, 0, 0, hovered and 160 or 100) + surface.DrawRect(0, 0, w, h) + + surface.SetDrawColor(pnl.hovered and PIS.Config.HighlightColor or Color(83, 83, 83)) + surface.DrawOutlinedRect(0, 0, w, h) + + draw.SimpleText(v.Name, "Nexus.PingSystem.Settings.Option.Name", 12, h / 2, hovered and color_white or Color(183, 183, 183), TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER) + end + + local options = v.Options and isfunction(v.Options) and v.Options() or v.Options + local optionsLen = options and #options or 0 + panel.Input = panel:Add( + v.Input == PSI_SETTINGS_SLIDER and "Nexus.PingSystem.Settings.Slider" + or (v.Input == PSI_SETTINGS_COMBOBOX and optionsLen != 2) and "Nexus.PingSystem.Settings.Combobox" + or v.Input == PSI_SETTINGS_COMBOBOX and "Nexus.PingSystem.Settings.Boolean" + or v.Input == PSI_SETTINGS_KEY and "Nexus.PingSystem.Settings.Key") + panel.Input:Dock(RIGHT) + panel.Input:DockMargin(8, 8, 8, 8) + panel.Input:SetWide(238) + + local default = isfunction(v.Default) and v.Default(PIS:GetSettings(LocalPlayer())) or 0 + if (v.Input == PSI_SETTINGS_SLIDER) then + panel.Input:SetMin(v.Min) + panel.Input:SetMax(v.Max) + panel.Input:OnValueChanged((default - v.Min) / (v.Max - v.Min)) + elseif (v.Input == PSI_SETTINGS_COMBOBOX) then + panel.Input:SetOptions(isfunction(v.Options) and v.Options() or v.Options) + panel.Input:SetSelected(default) + elseif (v.Input == PSI_SETTINGS_KEY) then + panel.Input.Key = default + end + + panel.Input.OnChange = v.OnChange + + panel.OnCursorEntered = function(pnl) + self:SetDescription(v.TitleReplacement or v.Name, v.Desc or "") + end + end +end + +function PANEL:PerformLayout(w, h) + self.Explain:SetWide(240) +end + +vgui.Register("Nexus.PingSystem.Settings.Wheel", PANEL) diff --git a/lua/infl_cmenu/vgui/windows.lua b/lua/infl_cmenu/vgui/windows.lua new file mode 100644 index 0000000..a26272a --- /dev/null +++ b/lua/infl_cmenu/vgui/windows.lua @@ -0,0 +1,182 @@ + + local inflexible = inflexible + + function PIS.OpenTextBox(text1, text2, cmd) + + + local bg = vgui.Create("DFrame") + bg:SetSize(400, 130) + bg:ShowCloseButton(false) + bg:MakePopup() + bg:Center() + bg.lblTitle:SetFont("infl.20") + bg:SetTitle(text1) + bg.Paint = function(self,w,h) draw.RoundedBox(0,0,0,w,h,Color(10,10,10,200)) end + + local label = vgui.Create("DLabel", bg) + label:Dock(TOP) + label:DockMargin(0,5,0,0) + label:SetWrap(true) + label:SetText(text2) + label:SetFont("infl.20") + label:SetTextColor(Color(255,255,255)) + + local exit = vgui.Create("DButton", bg) + exit:SetSize(20, 20) + exit:SetPos(bg:GetWide() - 22,2) + exit:SetText("r") + exit:SetFont("marlett") + exit:SetTextColor(Color(200,30,30)) + exit.Paint = function() end + exit.DoClick = function() bg:Close() end + + local myText = vgui.Create("DTextEntry", bg) + myText:Dock(TOP) + myText:SetTall(30) + myText:DockMargin(0,5,0,0) + myText:SetText("") + + local ybut = vgui.Create( "DButton", bg ) + ybut:Dock(TOP) + ybut:DockMargin(0,5,0,0) + ybut:SetTall(30) + ybut:SetText("Принять") + ybut:SetFont("infl.20") + ybut:SetTextColor(Color(255,255,255)) + ybut.Paint = function(self, w, h) draw.RoundedBox(0,0,0,w,h,Color(50,50,50)) end + + ybut.DoClick = function() + local amt = myText:GetValue() + local str = cmd.." "..amt + if amt then + RunConsoleCommand( "say", str ) + end + bg:Close() + textOpen = false + end + end + + function PIS.OpenPlyBox( text1, text2, cmd ) + + local bg = vgui.Create("DFrame") + bg:SetSize(400, 130) + bg:ShowCloseButton(false) + bg:MakePopup() + bg:Center() + bg.lblTitle:SetFont("infl.20") + bg:SetTitle(text1) + bg.Paint = function(self,w,h) draw.RoundedBox(0,0,0,w,h,Color(10,10,10,200)) end + + local label = vgui.Create("DLabel", bg) + label:Dock(TOP) + label:DockMargin(0,5,0,0) + label:SetWrap(true) + label:SetText(text2) + label:SetFont("infl.20") + label:SetTextColor(Color(255,255,255)) + + local exit = vgui.Create("DButton", bg) + exit:SetSize(20, 20) + exit:SetPos(bg:GetWide() - 22,2) + exit:SetText("r") + exit:SetFont("marlett") + exit:SetTextColor(Color(200,30,30)) + exit.Paint = function() end + exit.DoClick = function() bg:Close() end + + local hl = vgui.Create( "DComboBox", bg) + hl:Dock(TOP) + hl:DockMargin(0,5,0,0) + hl:SetTall(30) + for k,v in pairs(player.GetAll()) do hl:AddChoice(v:Name()) end + + hl.OnSelect = function(_,_,value) target = string.Explode(" ", value)[1] end + + local ybut = vgui.Create( "DButton", bg ) + ybut:Dock(TOP) + ybut:DockMargin(0,5,0,0) + ybut:SetTall(30) + ybut:SetText("Принять") + ybut:SetFont("infl.20") + ybut:SetTextColor(Color(255,255,255)) + ybut.Paint = function(self, w, h) draw.RoundedBox(0,0,0,w,h,Color(50,50,50)) end + ybut.DoClick = function() + local str = cmd.." "..target + if target then + RunConsoleCommand( "say", str ) + end + bg:Close() + textOpen = false + end + end + + function PIS.OpenPlyReasonBox( text1, text2, text3, cmd ) + + local bg = vgui.Create("DFrame") + bg:SetSize(400, 190) + bg:ShowCloseButton(false) + bg:MakePopup() + bg:Center() + bg.lblTitle:SetFont("infl.20") + bg:SetTitle(text1) + bg.Paint = function(self,w,h) draw.RoundedBox(0,0,0,w,h,Color(10,10,10,200)) end + + local label = vgui.Create("DLabel", bg) + label:Dock(TOP) + label:DockMargin(0,5,0,0) + label:SetWrap(true) + label:SetText(text2) + label:SetFont("infl.20") + label:SetTextColor(Color(255,255,255)) + + local exit = vgui.Create("DButton", bg) + exit:SetSize(20, 20) + exit:SetPos(bg:GetWide() - 22,2) + exit:SetText("r") + exit:SetFont("marlett") + exit:SetTextColor(Color(200,30,30)) + exit.Paint = function() end + exit.DoClick = function() bg:Close() end + + local target + + local hl = vgui.Create( "DComboBox", bg) + hl:Dock(TOP) + hl:DockMargin(0,5,0,0) + hl:SetTall(30) + for k,v in pairs(player.GetAll()) do hl:AddChoice(v:Name()) end + + hl.OnSelect = function(_,_,value) target = string.Explode(" ", value)[1] end + + local label2 = vgui.Create("DLabel", bg) + label2:Dock(TOP) + label2:DockMargin(0,5,0,0) + label2:SetWrap(true) + label2:SetText(text3) + label2:SetFont("infl.20") + label2:SetTextColor(Color(255,255,255)) + + local myText = vgui.Create("DTextEntry", bg) + myText:Dock(TOP) + myText:SetTall(30) + myText:DockMargin(0,5,0,0) + myText:SetText("") + + local ybut = vgui.Create( "DButton", bg ) + ybut:Dock(TOP) + ybut:DockMargin(0,5,0,0) + ybut:SetTall(30) + ybut:SetText("Принять") + ybut:SetFont("infl.20") + ybut:SetTextColor(Color(255,255,255)) + ybut.Paint = function(self, w, h) draw.RoundedBox(0,0,0,w,h,Color(50,50,50)) end + ybut.DoClick = function() + local amt = myText:GetValue() + local str = cmd.." "..target.." "..amt + if amt and target then + RunConsoleCommand( "say", str ) + end + bg:Close() + textOpen = false + end + end \ No newline at end of file diff --git a/lua/nexus_framework/core/class.lua b/lua/nexus_framework/core/class.lua new file mode 100644 index 0000000..180b79a --- /dev/null +++ b/lua/nexus_framework/core/class.lua @@ -0,0 +1,68 @@ +local CLASS = {} +CLASS.__constructor = function(self, name) end +CLASS.__data = {} +CLASS.__index = CLASS.__data + +AccessorFunc(CLASS, "m_acronym", "Acronym") + +function CLASS:SetConstructor(func) + self.__constructor = func +end + +function CLASS:Add(name, input) + self.__data[name] = input +end + +function CLASS:Get(name) + return self.__data[name] +end + +function CLASS:TernaryExistance(name, condition, success, failure) + local lookup = self:Get(name)[condition] + if (lookup) then + if (success) then + success(self, lookup) + end + else + if (failure) then + failure(self, lookup) + end + end +end + +function CLASS:Call(name, ...) + if (self.__data[name]) then + return self.__data[name](self, ...) + end +end + +function CLASS:Merge(name, input) + self.__data[name] = table.Merge(self:Get(name), input) +end + +function CLASS:Class(name, ...) + local acronym = self:GetAcronym() + + if (Nexus.Scripts[acronym].classManager[name]) then + return Nexus.Scripts[acronym].classManager[name] + end + + Nexus.Scripts[acronym].classManager[name] = self + self:__constructor(name, ...) + local col = Nexus.Scripts[acronym]:GetLoadColor() + + return self +end + +function Nexus:ClassManager(acronym) + if (Nexus.Scripts[acronym].classManager) then + return Nexus.Scripts[acronym].classManager + end + + local copy = table.Copy(CLASS) + copy:SetAcronym(acronym) + + Nexus.Scripts[acronym].classManager = copy + + return Nexus.Scripts[acronym].classManager +end \ No newline at end of file diff --git a/lua/nexus_framework/core/languages.lua b/lua/nexus_framework/core/languages.lua new file mode 100644 index 0000000..c5d6331 --- /dev/null +++ b/lua/nexus_framework/core/languages.lua @@ -0,0 +1,33 @@ +local framework = Nexus:ClassManager("Framework") +local settings = framework:Class("Settings") +local languages = framework:Class("Languages") + +languages:Add("Languages", {}) +languages:Add("GetActiveLanguage", function(self) + return settings:Call("Language") +end) +languages:Add("Register", function(self, script, language, data) + language = language:lower() + + self:TernaryExistance("Languages", script, nil, function(self, lookup) + lookup = {} + end) + self:Get("Languages")[script][language] = data +end) +languages:Add("GetTranslation", function(self, script, phrase, extraData) + local activeLanguage = self:Call("GetActiveLanguage") + + local lookup = self:Get("Languages")[script] + if (!lookup) then + return "Unknown script" + end + local tempLookup = lookup[activeLanguage] + lookup = lookup or lookup["english"] + lookup = lookup[phrase] or "Unknown phrase" + + return isfunction(lookup) and lookup(self, extraData, phrase, script) or lookup +end) + + + + diff --git a/lua/nexus_framework/core/load.lua b/lua/nexus_framework/core/load.lua new file mode 100644 index 0000000..e6f113e --- /dev/null +++ b/lua/nexus_framework/core/load.lua @@ -0,0 +1,81 @@ +Nexus.Scripts = Nexus.Scripts or {} + +local LOADER = {} +LOADER.__index = LOADER + +AccessorFunc(LOADER, "m_name", "Name") +AccessorFunc(LOADER, "m_acronym", "Acronym") +AccessorFunc(LOADER, "m_loadDirectory", "LoadDirectory") +AccessorFunc(LOADER, "m_color", "Color") + +LOADER.Realms = { + ["SERVER"] = SERVER and include or function() end, + ["CLIENT"] = CLIENT and include or AddCSLuaFile, + ["SHARED"] = function(path) + if (SERVER) then + include(path) + AddCSLuaFile(path) + else + include(path) + end + end +} + +function LOADER:GetRealm(realm) + realm = self.Realms[realm] + + if (realm) then + return realm + end +end + +function LOADER:GetLoadColor() + return self:GetColor() +end + +function LOADER:GetLoadMessage(realm, path) +end + +function LOADER:RegisterAcronym() + Nexus.Scripts[self:GetAcronym()] = self +end + +function LOADER:Load(dir, realm, recursive, ignoreFiles) + ignoreFiles = ignoreFiles or {} + local path = self:GetLoadDirectory() + if (!string.EndsWith(path, "/")) then path = path .. "/" end + if (!string.EndsWith(dir, "/")) then dir = dir .. "/" end + + realm = realm:upper() + local realmFunc = self:GetRealm(realm) + if (!realmFunc) then return end + + local files, folders = file.Find(path .. dir .. "*", "LUA") + + for fileIndex, file in ipairs(files) do + if (ignoreFiles[file]) then continue end + + local path = path .. dir .. file + self:GetLoadMessage(realm, path) + + realmFunc(path) + end + + if (recursive) then + for folderIndex, folder in ipairs(folders) do + self:Load(dir .. folder, realm, recursive, ignoreFiles) + end + end +end + +function LOADER:Register() + local time = SysTime() - self.start + time = math.Round(time, 4) .. "s" +end + +function Nexus:Loader() + local tbl = table.Copy(LOADER) + tbl.start = SysTime() + + return tbl +end \ No newline at end of file diff --git a/lua/nexus_framework/core/settings.lua b/lua/nexus_framework/core/settings.lua new file mode 100644 index 0000000..017e3f6 --- /dev/null +++ b/lua/nexus_framework/core/settings.lua @@ -0,0 +1,10 @@ +local framework = Nexus:ClassManager("Framework") +local settings = framework:Class("Settings") + +settings:Add("Config", {}) +settings:Add("GetEase", function(self) + return "Default" +end) +settings:Add("Language", function(self) + return self:Get("Config").Language +end) \ No newline at end of file diff --git a/lua/nexus_framework/core/testing.lua b/lua/nexus_framework/core/testing.lua new file mode 100644 index 0000000..c2b520e --- /dev/null +++ b/lua/nexus_framework/core/testing.lua @@ -0,0 +1,32 @@ +local framework = Nexus:ClassManager("Framework") +local testing = framework:Class("Testing") +testing:Add("Tests", {}) +testing:Add("Add", function(self, name, func) + self:Get("Tests")[name] = func +end) +testing:Add("AutoComplete", function(self, cmd, args) + local tests = self:Get("Tests") + + args = string.Trim(args) + args = string.lower(args) + + local tbl = {} + + for i, v in pairs(tests) do + if (i:lower():find(args)) then + table.insert(tbl, "nexus_test " .. i:lower()) + end + end + + return tbl +end) + +concommand.Add("nexus_test", function(ply, cmd, args) + local name = args[1] + local tbl = testing:Get("Tests")[name] + if (!tbl) then print("No such test") return end + + tbl(ply, cmd, args) +end, function(cmd, args) + return testing:Call("AutoComplete", cmd, args) +end) \ No newline at end of file diff --git a/lua/nexus_framework/core/themes.lua b/lua/nexus_framework/core/themes.lua new file mode 100644 index 0000000..da0c326 --- /dev/null +++ b/lua/nexus_framework/core/themes.lua @@ -0,0 +1 @@ +local x \ No newline at end of file diff --git a/lua/nexus_framework/database/wrapper.lua b/lua/nexus_framework/database/wrapper.lua new file mode 100644 index 0000000..da0c326 --- /dev/null +++ b/lua/nexus_framework/database/wrapper.lua @@ -0,0 +1 @@ +local x \ No newline at end of file diff --git a/lua/nexus_framework/vgui/components/avatar.lua b/lua/nexus_framework/vgui/components/avatar.lua new file mode 100644 index 0000000..640f072 --- /dev/null +++ b/lua/nexus_framework/vgui/components/avatar.lua @@ -0,0 +1,80 @@ +local PANEL = {} + +AccessorFunc(PANEL, "vertices", "Vertices") + +function PANEL:Init() + self:SetVertices(90) + + self.avatar = vgui.Create("AvatarImage", self) + self.avatar:SetPaintedManually(true) +end + +function PANEL:CalculatePoly(w, h) + local poly = {} + + local x = w/2 + local y = h/2 + local radius = h/2 + + table.insert(poly, { x = x, y = y }) + + for i = 0, self.vertices do + local a = math.rad((i / self.vertices) * -360) + 90 + table.insert(poly, { x = x + math.sin(a) * radius, y = y + math.cos(a) * radius }) + end + + local a = math.rad(0) + table.insert(poly, { x = x + math.sin(a) * radius, y = y + math.cos(a) * radius }) + self.data = poly +end + +function PANEL:PerformLayout(w, h) + self.avatar:SetPos(0, 0) + self.avatar:SetSize(w, h) + self:CalculatePoly(w, h) +end + +function PANEL:SetPlayer(ply, size) + self.avatar:SetPlayer(ply, size) +end + +function PANEL:SetSteamID(sid64, size) + self.avatar:SetSteamID(sid64, size) +end +function PANEL:DrawPoly( w, h ) + if (!self.data) then + self:CalculatePoly(w, h) + end + + surface.DrawPoly(self.data) +end + +function PANEL:Paint(w, h) + render.ClearStencil() + render.SetStencilEnable(true) + + render.SetStencilWriteMask(1) + render.SetStencilTestMask(1) + + render.SetStencilFailOperation(STENCILOPERATION_REPLACE) + render.SetStencilPassOperation(STENCILOPERATION_ZERO) + render.SetStencilZFailOperation(STENCILOPERATION_ZERO) + render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_NEVER) + render.SetStencilReferenceValue(1) + + draw.NoTexture() + surface.SetDrawColor(color_white) + self:DrawPoly(w, h) + + render.SetStencilFailOperation(STENCILOPERATION_ZERO) + render.SetStencilPassOperation(STENCILOPERATION_REPLACE) + render.SetStencilZFailOperation(STENCILOPERATION_ZERO) + render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL) + render.SetStencilReferenceValue(1) + + self.avatar:PaintManual() + + render.SetStencilEnable(false) + render.ClearStencil() +end +vgui.Register("Nexus.CircleAvatar", PANEL) \ No newline at end of file diff --git a/lua/nexus_framework/vgui/modules/animations.lua b/lua/nexus_framework/vgui/modules/animations.lua new file mode 100644 index 0000000..15bc0ae --- /dev/null +++ b/lua/nexus_framework/vgui/modules/animations.lua @@ -0,0 +1,45 @@ +local framework = Nexus:ClassManager("Framework") +local anim = framework:Class("Animations") +local settings = framework:Class("Settings") + +anim:Add("Eases", { + Default = function(t, b, c, d) + t = t / d + local ts = t * t + local tc = ts * t + + return b + c * (-2 * tc + 3 * ts) + end +}) +anim:Add("Ease", function(self, ease, ...) + return self:Get("Eases")[ease](...) +end) +anim:Add("LerpColor", function(self, fraction, from, to) + return Color( + Lerp(fraction, from.r, to.r), + Lerp(fraction, from.g, to.g), + Lerp(fraction, from.b, to.b), + Lerp(fraction, from.a or 255, to.a or 255) + ) +end) +anim:Add("AnimateColor", function(self, pnl, var, toCol, duration, ease, callback) + duration = duration or 0.2 + ease = ease or settings:Call("GetEase") + + local col = pnl[var] + local anim = pnl:NewAnimation(duration) + anim.Color = toCol + anim.Think = function(anim, pnl, fraction) + local _fract = self:Call("Ease", ease, fraction, 0, 1, 1) + + if (!anim.StartColor) then + anim.StartColor = col + end + + local newCol = self:Call("LerpColor", _fract, anim.StartColor, anim.Color) + pnl[var] = newCol + end + anim.OnEnd = function() + if (callback) then callback(pnl) end + end +end) diff --git a/lua/nexus_framework/vgui/modules/draw.lua b/lua/nexus_framework/vgui/modules/draw.lua new file mode 100644 index 0000000..80a70d9 --- /dev/null +++ b/lua/nexus_framework/vgui/modules/draw.lua @@ -0,0 +1,330 @@ + +local framework = Nexus:ClassManager("Framework") +local _draw = draw +local draw = framework:Class("Draw") + +local sin = math.sin +local cos = math.cos +local rad = math.rad + +local surface = surface +local render = render + +-- Reformatted https://gist.github.com/theawesomecoder61/d2c3a3d42bbce809ca446a85b4dda754 +draw:Add("Arc", function(self, cx, cy, radius, thickness, startang, endang, roughness,color) + surface.SetDrawColor(color) + + local arc = self:Call("PrecacheArc", + cx, + cy, + radius, + thickness, + startang, + endang, + roughness + ) + + for i, vertex in ipairs(arc) do + surface.DrawPoly(vertex) + end +end) + +draw:Add("PrecacheArc", function(self, cx, cy, radius, thickness, startang, endang, roughness) + local triarc = {} + -- local deg2rad = math.pi / 180 + + -- Define step + local roughness = math.max(roughness or 1, 1) + local step = roughness + + -- Correct start/end ang + local startang,endang = startang or 0, endang or 0 + + if startang > endang then + step = math.abs(step) * -1 + end + + -- Create the inner circle's points. + local inner = {} + local r = radius - thickness + for deg=startang, endang, step do + local rad = rad(deg) + -- local rad = deg2rad * deg + local ox, oy = cx+(cos(rad)*r), cy+(-sin(rad)*r) + table.insert(inner, { + x=ox, + y=oy, + u=(ox-cx)/radius + .5, + v=(oy-cy)/radius + .5, + }) + end + + -- Create the outer circle's points. + local outer = {} + for deg=startang, endang, step do + local rad = rad(deg) + -- local rad = deg2rad * deg + local ox, oy = cx+(cos(rad)*radius), cy+(-sin(rad)*radius) + table.insert(outer, { + x=ox, + y=oy, + u=(ox-cx)/radius + .5, + v=(oy-cy)/radius + .5, + }) + end + + -- Triangulize the points. + for tri=1,#inner*2 do -- twice as many triangles as there are degrees. + local p1,p2,p3 + p1 = outer[math.floor(tri/2)+1] + p3 = inner[math.floor((tri+1)/2)+1] + if tri%2 == 0 then --if the number is even use outer. + p2 = outer[math.floor((tri+1)/2)] + else + p2 = inner[math.floor((tri+1)/2)] + end + + table.insert(triarc, {p1,p2,p3}) + end + + -- Return a table of triangles to draw. + return triarc +end) + +draw:Add("CachedArc",function(self,arc,col) + + surface.SetDrawColor(col) + for i, vertex in ipairs(arc) do + surface.DrawPoly(vertex) + end + +end) + +-- https://forum.facepunch.com/gmoddev/mtdf/I-need-help-making-a-blurred-derma-panel/1/ +local blur = Material("pp/blurscreen") +draw:Add("Blur", function(self, panel, intensivity, d) + local x, y = panel:LocalToScreen() + surface.SetDrawColor(color_white) + surface.SetMaterial(blur) + + for i = 1, intensivity do + blur:SetFloat("$blur", (i / d) * intensivity) + blur:Recompute() + + render.UpdateScreenEffectTexture() + + surface.DrawTexturedRect(-x, -y, ScrW(), ScrH()) + end +end) +-- Somewhere on facepunch +draw:Add("BlurHUD", function(self, x, y, w, h, amt) + local X, Y = 0,0 + + surface.SetDrawColor(255,255,255) + surface.SetMaterial(blur) + + for i = 1, amt or 5 do + blur:SetFloat("$blur", (i / 3) * (5)) + blur:Recompute() + + render.UpdateScreenEffectTexture() + + render.SetScissorRect(x, y, x+w, y+h, true) + surface.DrawTexturedRect(X * -1, Y * -1, ScrW(), ScrH()) + render.SetScissorRect(0, 0, 0, 0, false) + end +end) + +-- Inflexible +draw:Add("PrecacheCircle", function(self, sx, sy, radius, vertexCount, angle) + local vertices = {} + local ang = -rad(angle or 0) + local c = cos(ang) + local s = sin(ang) + for i = 0, 360, 360 / vertexCount do + local radd = rad(i) + local x = cos(radd) + local y = sin(radd) + + local tempx = x * radius * c - y * radius * s + sx + y = x * radius * s + y * radius * c + sy + x = tempx + + vertices[#vertices + 1] = { + x = x, + y = y, + u = u, + v = v + } + end + + return vertices +end) + +-- Found on some GitHub repository a long time ago +-- Inflexible редакция +draw:Add("Circle", function(self, sx, sy, radius, vertexCount, color, angle) + + local vertices = self:Call("PrecacheCircle", + sx, + sy, + radius, + vertexCount, + angle + ) + + if vertices and #vertices > 0 then + _draw.NoTexture() + surface.SetDrawColor(color) + surface.DrawPoly(vertices) + end +end) + +-- Inflexible +draw:Add("CachedCircle", function(self,circle,color) + if circle and #circle > 0 then + _draw.NoTexture() + surface.SetDrawColor(color) + surface.DrawPoly(circle) + end +end) + +draw:Add("ShadowText", function(self, str, font, x, y, col, xAlign, yAlign) + _draw.SimpleText(str, font, x - 1, y - 1, color_black, xAlign, yAlign) + _draw.SimpleText(str, font, x - 1, y + 1, color_black, xAlign, yAlign) + _draw.SimpleText(str, font, x + 1, y - 1, color_black, xAlign, yAlign) + _draw.SimpleText(str, font, x + 1, y + 1, color_black, xAlign, yAlign) + + _draw.SimpleText(str, font, x, y, col, xAlign, yAlign) +end) + +-- https://github.com/Bo98/garrysmod-util/blob/master/lua/autorun/client/gradient.lua +-- Gradient helper functions +-- By Bo Anderson +-- Licensed under Mozilla Public License v2.0 +local mat_white = Material("vgui/white") +draw:Add("SimpleLinearGradient", function(self, x, y, w, h, startColor, endColor, horizontal) + self:Call("LinearGradient", x, y, w, h, { {offset = 0, color = startColor}, {offset = 1, color = endColor} }, horizontal) +end) + +draw:Add("LinearGradient", function(self, x, y, w, h, stops, horizontal) + if #stops == 0 then + return + elseif #stops == 1 then + surface.SetDrawColor(stops[1].color) + surface.DrawRect(x, y, w, h) + return + end + + table.SortByMember(stops, "offset", true) + + render.SetMaterial(mat_white) + mesh.Begin(MATERIAL_QUADS, #stops - 1) + for i = 1, #stops - 1 do + local offset1 = math.Clamp(stops[i].offset, 0, 1) + local offset2 = math.Clamp(stops[i + 1].offset, 0, 1) + if offset1 == offset2 then continue end + + local deltaX1, deltaY1, deltaX2, deltaY2 + + local color1 = stops[i].color + local color2 = stops[i + 1].color + + local r1, g1, b1, a1 = color1.r, color1.g, color1.b, color1.a + local r2, g2, b2, a2 + local r3, g3, b3, a3 = color2.r, color2.g, color2.b, color2.a + local r4, g4, b4, a4 + + if horizontal then + r2, g2, b2, a2 = r3, g3, b3, a3 + r4, g4, b4, a4 = r1, g1, b1, a1 + deltaX1 = offset1 * w + deltaY1 = 0 + deltaX2 = offset2 * w + deltaY2 = h + else + r2, g2, b2, a2 = r1, g1, b1, a1 + r4, g4, b4, a4 = r3, g3, b3, a3 + deltaX1 = 0 + deltaY1 = offset1 * h + deltaX2 = w + deltaY2 = offset2 * h + end + + mesh.Color(r1, g1, b1, a1) + mesh.Position(Vector(x + deltaX1, y + deltaY1)) + mesh.AdvanceVertex() + + mesh.Color(r2, g2, b2, a2) + mesh.Position(Vector(x + deltaX2, y + deltaY1)) + mesh.AdvanceVertex() + + mesh.Color(r3, g3, b3, a3) + mesh.Position(Vector(x + deltaX2, y + deltaY2)) + mesh.AdvanceVertex() + + mesh.Color(r4, g4, b4, a4) + mesh.Position(Vector(x + deltaX1, y + deltaY2)) + mesh.AdvanceVertex() + end + mesh.End() +end) + +-- Based off the stencil operations found in the code in @vgui/components/avatar.lua +draw:Add("MaskInclude", function(self, maskFunc, renderFunc) + render.ClearStencil() + render.SetStencilEnable(true) + render.DepthRange(0, 1) + + render.SetStencilWriteMask(1) + render.SetStencilTestMask(1) + + render.SetStencilFailOperation(STENCILOPERATION_REPLACE) + render.SetStencilPassOperation(STENCILOPERATION_ZERO) + render.SetStencilZFailOperation(STENCILOPERATION_ZERO) + render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_NEVER) + render.SetStencilReferenceValue(1) + + maskFunc() + + render.SetStencilFailOperation(STENCILOPERATION_ZERO) + render.SetStencilPassOperation(STENCILOPERATION_REPLACE) + render.SetStencilZFailOperation(STENCILOPERATION_ZERO) + render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL) + render.SetStencilReferenceValue(1) + + renderFunc() + + render.DepthRange(0, 1) + render.SetStencilEnable(false) + render.ClearStencil() +end) + +draw:Add("MaskExclude", function(self, maskFunc, renderFunc) + render.ClearStencil() + render.SetStencilEnable(true) + render.DepthRange(0, 1) + + render.SetStencilWriteMask(1) + render.SetStencilTestMask(1) + + render.SetStencilFailOperation(STENCILOPERATION_REPLACE) + render.SetStencilPassOperation(STENCILOPERATION_REPLACE) + render.SetStencilZFailOperation(STENCILOPERATION_ZERO) + render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_NEVER) + render.SetStencilReferenceValue(1) + + maskFunc() + + render.SetStencilFailOperation(STENCILOPERATION_REPLACE) + render.SetStencilPassOperation(STENCILOPERATION_REPLACE) + render.SetStencilZFailOperation(STENCILOPERATION_ZERO) + render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL) + render.SetStencilReferenceValue(0) + + renderFunc() + + render.DepthRange(0, 1) + render.SetStencilEnable(false) + render.ClearStencil() +end) \ No newline at end of file diff --git a/lua/nexus_framework/vgui/modules/panels.lua b/lua/nexus_framework/vgui/modules/panels.lua new file mode 100644 index 0000000..0155a60 --- /dev/null +++ b/lua/nexus_framework/vgui/modules/panels.lua @@ -0,0 +1,13 @@ +local framework = Nexus:ClassManager("Framework") +local panels = framework:Class("Panels") +local anim = framework:Class("Animations") + +panels:Add("Create", function(self, pnlName, parent) + local panel = vgui.Create(pnlName, parent) + panel.__anim = anim + panel.Anim = function(pnl) + return pnl.__anim + end + + return panel +end) \ No newline at end of file