mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
1208 lines
45 KiB
Lua
1208 lines
45 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
AddCSLuaFile()
|
|
|
|
ParticleListTable = {
|
|
Games = {},
|
|
Addons = {},
|
|
}
|
|
|
|
local doubleslash = "//"
|
|
|
|
|
|
local function AddToParticleListTable(filename,isaddon,icon)
|
|
|
|
//Converts a list string, with one item per line, into a table, taking comments and empty strings into account. Returns nil if the table is empty.
|
|
//The format of these tables is item1 = true, item2 = true, etc., not 1 = item1, 2 = item2, etc.; this is so we can use "if table["itemX"] then" to check if a value is inside of it.
|
|
//
|
|
//Instead of the arg being the string itself, the args are 1: the table containing the string, and 2: the key the string can be found at.
|
|
//This is so we can find continuations of the string, which'll be in the same table, but under separate keys.
|
|
//
|
|
local function ListStringToTable(listcontainer,listname)
|
|
//Find the list string we're looking for inside the container, and explode it into its own table.
|
|
local liststring = listcontainer[listname]
|
|
if type(liststring) != "string" then MsgN("PARTICLE CONTROL ERROR: List string \"" .. listname .. "\" inside of \"" .. filename .. "\" doesn't seem to actually be a string! Check the file and make sure you've formatted everything correctly!") return end
|
|
if #liststring == 4095 then MsgN("PARTICLE CONTROL ERROR: List string \"" .. listname .. "\" inside of \"" .. filename .. "\" is more than 4095 characters long - that's too long for the engine to read all of it! Split it up into multiple lists!") end
|
|
local listtab = string.Explode("\n", liststring)
|
|
|
|
//Also find any list strings that are continuations of our main list string, and explode them into the same table.
|
|
for listname2, liststring2 in pairs (listcontainer) do
|
|
if string.StartWith(listname2, listname .. "_cont") then
|
|
if type(liststring) != "string" then MsgN("PARTICLE CONTROL ERROR: List string \"" .. listname2 .. "\" inside of \"" .. filename .. "\" doesn't seem to actually be a string! Check the file and make sure you've formatted everything correctly!") return end
|
|
if #liststring2 == 4095 then MsgN("PARTICLE CONTROL ERROR: List string \"" .. listname2 .. "\" inside of \"" .. filename .. "\" is more than 4095 characters long - that's too long for the engine to read all of it! Split it up into multiple lists!") end
|
|
table.Add(listtab, string.Explode("\n", liststring2) )
|
|
end
|
|
end
|
|
|
|
//Finally, filter out any comments or blank spaces from the table.
|
|
local listtabfiltered = {}
|
|
for _, str in pairs (listtab) do
|
|
//if there's a doubleslash in the string then remove it and everything after it
|
|
local commentpos, _ = string.find(str, doubleslash)
|
|
local resultstr = str
|
|
if commentpos then
|
|
resultstr = string.sub( str, 1, commentpos - 1 )
|
|
end
|
|
|
|
//trim any spaces from the string, and don't add it to the filtered table if it's just an empty string at this point
|
|
resultstr = string.Trim(resultstr)
|
|
if resultstr != "" then listtabfiltered[resultstr] = true end
|
|
end
|
|
if table.Count(listtabfiltered) > 0 then
|
|
return listtabfiltered
|
|
end
|
|
end
|
|
|
|
local filestr = file.Read(filename,"LUA")
|
|
if !filestr then MsgN("PARTICLE CONTROL ERROR: Particle list file \"" .. filename .. "\" doesn't exist or isn't a readable file! Something went wrong!") return end
|
|
local keyvalues = util.KeyValuesToTable( filestr, false, true )
|
|
local resulttable = { Info = {}, Particles = {} }
|
|
if !keyvalues or (table.Count(keyvalues) == 0) then MsgN("PARTICLE CONTROL ERROR: Particle list file \"" .. filename .. "\" isn't a valid keyvalue table and couldn't be read! Check the file and make sure you've formatted everything correctly!") return end
|
|
if !keyvalues.Info then
|
|
//On Mac/Linux systems, the keyvalues-to-table function messes up and returns the keyname "Info" as something else, like "inf", so it's possible that the info subtable is
|
|
//still here, just under a different keyname. The info is the only thing in keyvalues that should be a table value, so we'll check for that:
|
|
local foundinfo = false
|
|
for k, v in pairs (keyvalues) do
|
|
if type(v) == "table" then
|
|
keyvalues.Info = v
|
|
MsgN("(" .. filename .. ": Found Info table under keyname " .. tostring(k) .. ")")
|
|
foundinfo = true
|
|
end
|
|
end
|
|
//If there's no table value in keyvalues at all, then this is a probably a custom file where someone messed up the formatting.
|
|
if !foundinfo then
|
|
MsgN("PARTICLE CONTROL ERROR: Particle list file \"" .. filename .. "\" doesn't have an \"Info\" table that we can find! Check the file and make sure you've formatted everything correctly!")
|
|
return
|
|
end
|
|
end
|
|
if !keyvalues.Info.CategoryName then MsgN("PARTICLE CONTROL ERROR: Particle list file \"" .. filename .. "\"'s Info table doesn't have a \"CategoryName\" string that we can find! Check the file and make sure you've formatted everything correctly!") return end
|
|
|
|
resulttable.Info.CategoryName = keyvalues.Info.CategoryName
|
|
resulttable.Info.Icon = icon
|
|
resulttable.Info.EffectOptions = {}
|
|
if keyvalues.Info["EffectOptions"] then
|
|
if keyvalues.Info.EffectOptions["Beams"] then
|
|
resulttable.Info.EffectOptions["Beams"] = ListStringToTable(keyvalues.Info.EffectOptions, "Beams")
|
|
end
|
|
if keyvalues.Info.EffectOptions["Color1"] then
|
|
resulttable.Info.EffectOptions["Color1"] = ListStringToTable(keyvalues.Info.EffectOptions, "Color1")
|
|
end
|
|
if keyvalues.Info.EffectOptions["Color255"] then
|
|
resulttable.Info.EffectOptions["Color255"] = ListStringToTable(keyvalues.Info.EffectOptions, "Color255")
|
|
end
|
|
if keyvalues.Info.EffectOptions["Tracers"] then
|
|
resulttable.Info.EffectOptions["Tracers"] = ListStringToTable(keyvalues.Info.EffectOptions, "Tracers")
|
|
end
|
|
end
|
|
if keyvalues.Info["UtilEffects"] then
|
|
resulttable.Info["UtilEffects"] = keyvalues.Info["UtilEffects"]
|
|
end
|
|
keyvalues.Info = nil
|
|
|
|
|
|
for k, _ in pairs (keyvalues) do
|
|
if !string.StartWith(k,doubleslash) and string.EndsWith(k, ".pcf") then //ignore .pcf lists that start with a doubleslash; also ignore lists that don't end with .pcf since these are probably continuations
|
|
local particlelist = ListStringToTable(keyvalues, k)
|
|
if particlelist then
|
|
game.AddParticles("particles/" .. k)
|
|
resulttable.Particles[k] = particlelist
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local subtablename = string.StripExtension( string.GetFileFromFilename(filename) )
|
|
if isaddon then
|
|
MsgN( "PARTICLE CONTROL: Added list for addon: " .. resulttable.Info.CategoryName )
|
|
ParticleListTable.Addons[subtablename] = resulttable
|
|
else
|
|
MsgN( "PARTICLE CONTROL: Added list for game: " .. resulttable.Info.CategoryName )
|
|
ParticleListTable.Games[subtablename] = resulttable
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
//Source Engine / Garry's Mod
|
|
AddToParticleListTable("particlelists/gmod.lua", false, "games/16/garrysmod.png")
|
|
|
|
//Team Fortress 2
|
|
if IsMounted("tf") then
|
|
AddToParticleListTable("particlelists/tf2.lua", false, "games/16/tf.png") //TODO: currently causes a crash when loading updated pcfs, uncomment once fixed by devs
|
|
end
|
|
|
|
//Half-Life 2: Episode 1
|
|
if IsMounted("episodic") then
|
|
AddToParticleListTable("particlelists/ep1.lua", false, "games/16/episodic.png")
|
|
end
|
|
|
|
//Half-Life 2: Episode 2
|
|
if IsMounted("ep2") then
|
|
AddToParticleListTable("particlelists/ep2.lua", false, "games/16/ep2.png")
|
|
end
|
|
|
|
//Portal
|
|
if IsMounted("portal") then
|
|
AddToParticleListTable("particlelists/portal.lua", false, "games/16/portal.png")
|
|
end
|
|
|
|
//Counter-Strike: Source
|
|
if IsMounted("cstrike") then
|
|
AddToParticleListTable("particlelists/cstrike.lua", false, "games/16/cstrike.png")
|
|
end
|
|
|
|
|
|
//Find all list files in the particlelists/addons/ directory, and add them to their own section of the table
|
|
local alladdons, _ = file.Find( "lua/particlelists/addons/*.lua", "GAME" )
|
|
for _, filename in pairs (alladdons) do
|
|
if !string.StartWith( filename, "_" ) then //don't add files that start with an _, this is how we stop it from reading the example files
|
|
AddToParticleListTable("particlelists/addons/" .. filename, true, "icon16/bricks.png")
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
if CLIENT then
|
|
|
|
//Favorites - this table is global because it's used by every Particle Browser panel on the client
|
|
ParticleBrowserFavorites = {
|
|
Effects = {}, //effects in the favorites list
|
|
Children = {}, //all DTreeNode panels that are using this favorites list
|
|
}
|
|
|
|
local parctrlfavs_str = file.Read("particlecontrol_favorites.txt","DATA")
|
|
if parctrlfavs_str then ParticleBrowserFavorites.Effects = util.JSONToTable(parctrlfavs_str) end
|
|
|
|
|
|
function ParticleBrowserFavorites_UpdateEffect( effectdisplay, effectoptions )
|
|
|
|
if effectoptions then
|
|
//We're adding the effect
|
|
ParticleBrowserFavorites.Effects[effectdisplay] = effectoptions
|
|
else
|
|
//We're removing the effect
|
|
ParticleBrowserFavorites.Effects[effectdisplay] = nil
|
|
end
|
|
|
|
for _, panel in pairs (ParticleBrowserFavorites.Children) do
|
|
if panel then
|
|
ParticleBrowserFavorites_UpdateChildPanel( panel )
|
|
end
|
|
end
|
|
|
|
file.Write( "particlecontrol_favorites.txt", util.TableToJSON(ParticleBrowserFavorites.Effects, true) )
|
|
|
|
end
|
|
|
|
|
|
function ParticleBrowserFavorites_UpdateChildPanel( panel )
|
|
|
|
if !panel then return end
|
|
|
|
if panel.FavoriteNodes then
|
|
//Remove all of the nodes from the panel
|
|
for k, node in pairs (panel.FavoriteNodes) do
|
|
node:Remove()
|
|
panel.FavoriteNodes[k] = nil
|
|
end
|
|
else
|
|
panel.FavoriteNodes = {}
|
|
end
|
|
|
|
for effectdisplay, effectoptions in SortedPairs (ParticleBrowserFavorites.Effects) do
|
|
local effect = effectoptions["InternalName"]
|
|
|
|
panel.FavoriteNodes[effect] = panel:AddNode(effectdisplay)
|
|
|
|
panel.FavoriteNodes[effect].EffectOptions = {}
|
|
if effectoptions["Beam"] then
|
|
panel.FavoriteNodes[effect].EffectOptions["Beam"] = true
|
|
end
|
|
if effectoptions["Colorable"] then
|
|
panel.FavoriteNodes[effect].EffectOptions["Colorable"] = true
|
|
end
|
|
if effectoptions["ColorOutOfOne"] then
|
|
panel.FavoriteNodes[effect].EffectOptions["ColorOutOfOne"] = true
|
|
end
|
|
|
|
//Don't use the icons for features we're not using
|
|
local beamicon = ( (panel.CommandInfo.mode_beam) and (panel.FavoriteNodes[effect].EffectOptions["Beam"] == true) )
|
|
local coloricon = ( (panel.CommandInfo.color) and (panel.FavoriteNodes[effect].EffectOptions["Colorable"] == true) )
|
|
//Set the effect icon:
|
|
if beamicon and coloricon then
|
|
panel.FavoriteNodes[effect].Icon:SetImage("icon16/fire_line_rainbow.png")
|
|
elseif beamicon then
|
|
panel.FavoriteNodes[effect].Icon:SetImage("icon16/fire_line.png")
|
|
elseif coloricon then
|
|
panel.FavoriteNodes[effect].Icon:SetImage("icon16/fire_rainbow.png")
|
|
else
|
|
panel.FavoriteNodes[effect].Icon:SetImage("icon16/fire.png")
|
|
end
|
|
|
|
panel.FavoriteNodes[effect].DoClick = function()
|
|
RunConsoleCommand( panel.CommandInfo.effectname, effect )
|
|
|
|
if panel.CommandInfo.mode_beam then
|
|
if panel.FavoriteNodes[effect].EffectOptions["Beam"] then
|
|
RunConsoleCommand( panel.CommandInfo.mode_beam, "1" )
|
|
else
|
|
RunConsoleCommand( panel.CommandInfo.mode_beam, "0" )
|
|
end
|
|
end
|
|
|
|
if panel.CommandInfo.color then
|
|
if panel.FavoriteNodes[effect].EffectOptions["Colorable"] then
|
|
RunConsoleCommand( panel.CommandInfo.color .. "_enabled", "1" )
|
|
else
|
|
RunConsoleCommand( panel.CommandInfo.color .. "_enabled", "0" )
|
|
end
|
|
|
|
if panel.FavoriteNodes[effect].EffectOptions["ColorOutOfOne"] then
|
|
RunConsoleCommand( panel.CommandInfo.color .. "_outofone", "1" )
|
|
else
|
|
RunConsoleCommand( panel.CommandInfo.color .. "_outofone", "0" )
|
|
end
|
|
end
|
|
end
|
|
|
|
panel.FavoriteNodes[effect].DoRightClick = function()
|
|
//We only need the remove option here, since it's already in the favorites list
|
|
local menu = DermaMenu()
|
|
|
|
local option = menu:AddOption( "Un-favorite \'\'" .. effectdisplay .. "\'\'", function()
|
|
ParticleBrowserFavorites_UpdateEffect( effectdisplay ) //calling this function with no second arg tells it to remove this effect from the list
|
|
end )
|
|
option:SetImage("icon16/delete.png")
|
|
|
|
menu:Open()
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function AddParticleBrowser(panel,data)
|
|
|
|
local self = {}
|
|
|
|
//Data table contents:
|
|
//{
|
|
//name = "Effect" (name to show at the top of the panel)
|
|
//commands = (table of concommands that the panel uses)
|
|
// {
|
|
// effectname = "particlecontrol_effectname"
|
|
// mode_beam = "particlecontrol_mode_beam" (optional)
|
|
// color = "particlecontrol_color" (optional, assumes there are cvars derived from this name (X_enabled, X_r, X_g, X_b, X_outofone) )
|
|
// utileffect = "particlecontrol_utileffect" (optional, assumes there are cvars derived from this name (X_scale, X_magnitude, X_radius) )
|
|
//
|
|
// enabled = "particlecontrol_enabled" (optional - toggles whether or not the panel is open using this cvar)
|
|
// }
|
|
//}
|
|
|
|
self.back = vgui.Create("DForm", panel)
|
|
self.back:SetLabel(data.name)
|
|
self.back.Paint = function()
|
|
derma.SkinHook( "Paint", "CollapsibleCategory", self.back, self.back:GetWide(), self.back:GetTall() )
|
|
surface.SetDrawColor( Color(0,0,0,70) )
|
|
surface.DrawRect( 0, 0, self.back:GetWide(), self.back:GetTall() )
|
|
end
|
|
self.back.Header:SetImage("icon16/fire.png")
|
|
self.back.Header.DoClick = function() end
|
|
panel:AddPanel(self.back)
|
|
|
|
|
|
|
|
|
|
self.tree = vgui.Create("DTree", self.back)
|
|
self.tree:SetHeight(400)
|
|
self.back:AddItem(self.tree)
|
|
self.tree:GetParent():DockPadding(5,5,5,0)
|
|
|
|
local function PopulateEffectList(parent, effectstab, effectoptions)
|
|
for k, v in SortedPairs (effectstab) do
|
|
local effect = k
|
|
local effectdisplay = k
|
|
//if v is another string instead of just a filler "true" value, then that means k is the display name and v is the internal name
|
|
if isstring(v) then
|
|
effect = v
|
|
end
|
|
|
|
parent[effect] = parent:AddNode(effectdisplay)
|
|
|
|
parent[effect].EffectOptions = {}
|
|
if effectoptions["Beams"] and effectoptions["Beams"][effect] then
|
|
parent[effect].EffectOptions["Beam"] = true
|
|
end
|
|
if effectoptions["Color1"] and effectoptions["Color1"][effect] then
|
|
parent[effect].EffectOptions["Colorable"] = true
|
|
parent[effect].EffectOptions["ColorOutOfOne"] = true
|
|
end
|
|
if effectoptions["Color255"] and effectoptions["Color255"][effect] then
|
|
parent[effect].EffectOptions["Colorable"] = true
|
|
parent[effect].EffectOptions["ColorOutOfOne"] = false
|
|
end
|
|
|
|
//Don't use the icons for features we're not using
|
|
local beamicon = ( (data.commands.mode_beam) and (parent[effect].EffectOptions["Beam"] == true) )
|
|
local coloricon = ( (data.commands.color) and (parent[effect].EffectOptions["Colorable"] == true) )
|
|
//Set the effect icon:
|
|
if beamicon and coloricon then
|
|
parent[effect].Icon:SetImage("icon16/fire_line_rainbow.png")
|
|
elseif beamicon then
|
|
parent[effect].Icon:SetImage("icon16/fire_line.png")
|
|
elseif coloricon then
|
|
parent[effect].Icon:SetImage("icon16/fire_rainbow.png")
|
|
else
|
|
parent[effect].Icon:SetImage("icon16/fire.png")
|
|
end
|
|
|
|
//Left Click: Select the effect by setting its concommands
|
|
parent[effect].DoClick = function()
|
|
RunConsoleCommand( data.commands.effectname, effect )
|
|
|
|
if data.commands.mode_beam then
|
|
if parent[effect].EffectOptions["Beam"] then
|
|
RunConsoleCommand( data.commands.mode_beam, "1" )
|
|
else
|
|
RunConsoleCommand( data.commands.mode_beam, "0" )
|
|
end
|
|
end
|
|
|
|
if data.commands.color then
|
|
if parent[effect].EffectOptions["Colorable"] then
|
|
RunConsoleCommand( data.commands.color .. "_enabled", "1" )
|
|
else
|
|
RunConsoleCommand( data.commands.color .. "_enabled", "0" )
|
|
end
|
|
|
|
if parent[effect].EffectOptions["ColorOutOfOne"] then
|
|
RunConsoleCommand( data.commands.color .. "_outofone", "1" )
|
|
else
|
|
RunConsoleCommand( data.commands.color .. "_outofone", "0" )
|
|
end
|
|
end
|
|
end
|
|
|
|
//Right Click: Display an option to add/remove the effect from favorites
|
|
parent[effect].DoRightClick = function()
|
|
local menu = DermaMenu()
|
|
|
|
if !ParticleBrowserFavorites.Effects[effectdisplay] then
|
|
local option = menu:AddOption( "Favorite \'\'" .. effectdisplay .. "\'\'", function()
|
|
ParticleBrowserFavorites_UpdateEffect( effectdisplay, {
|
|
["InternalName"] = effect,
|
|
["Beam"] = tobool(parent[effect].EffectOptions["Beam"]),
|
|
["Colorable"] = tobool(parent[effect].EffectOptions["Colorable"]),
|
|
["ColorOutOfOne"] = tobool(parent[effect].EffectOptions["ColorOutOfOne"]),
|
|
} )
|
|
end )
|
|
option:SetImage("icon16/add.png")
|
|
else
|
|
local option = menu:AddOption( "Un-favorite \'\'" .. effectdisplay .. "\'\'", function()
|
|
ParticleBrowserFavorites_UpdateEffect( effectdisplay ) //calling this function with no second arg tells it to remove this effect from the list
|
|
end )
|
|
option:SetImage("icon16/delete.png")
|
|
end
|
|
|
|
menu:Open()
|
|
end
|
|
end
|
|
end
|
|
|
|
//Games
|
|
self.tree.games = self.tree:AddNode("Games")
|
|
self.tree.games.Icon:SetImage("icon16/folder_database.png")
|
|
self.tree.games:SetExpanded(true)
|
|
//
|
|
for tabname, tab in SortedPairs (ParticleListTable.Games) do
|
|
self.tree.games[tabname] = self.tree.games:AddNode(tab.Info.CategoryName)
|
|
self.tree.games[tabname].Icon:SetImage(tab.Info.Icon)
|
|
|
|
//Create the utilfx list
|
|
if tab.Info.UtilEffects then
|
|
self.tree.games[tabname].UtilEffects = self.tree.games[tabname]:AddNode("Scripted Effects")
|
|
self.tree.games[tabname].UtilEffects.Icon:SetImage("icon16/page_gear.png")
|
|
|
|
self.tree.games[tabname].UtilEffects.IsPopulated = false
|
|
self.tree.games[tabname].UtilEffects.DoClick = function()
|
|
if self.tree.games[tabname].UtilEffects.IsPopulated == true then return end
|
|
|
|
PopulateEffectList(self.tree.games[tabname].UtilEffects, tab.Info.UtilEffects, tab.Info.EffectOptions)
|
|
|
|
self.tree.games[tabname].UtilEffects.IsPopulated = true
|
|
self.tree.games[tabname].UtilEffects:SetExpanded(true)
|
|
end
|
|
end
|
|
|
|
//Create the .pcf lists
|
|
for pcfname, particles in SortedPairs (tab.Particles) do
|
|
local pcftabname = string.StripExtension(pcfname) //just in case having a dot in the key name causes problems
|
|
self.tree.games[tabname][pcftabname] = self.tree.games[tabname]:AddNode(pcfname)
|
|
self.tree.games[tabname][pcftabname].Icon:SetImage("icon16/page.png")
|
|
|
|
self.tree.games[tabname][pcftabname].IsPopulated = false
|
|
self.tree.games[tabname][pcftabname].DoClick = function()
|
|
if self.tree.games[tabname][pcftabname].IsPopulated == true then return end
|
|
|
|
PopulateEffectList(self.tree.games[tabname][pcftabname], particles, tab.Info.EffectOptions)
|
|
|
|
self.tree.games[tabname][pcftabname].IsPopulated = true
|
|
self.tree.games[tabname][pcftabname]:SetExpanded(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
//Addons
|
|
self.tree.addons = self.tree:AddNode("Addons")
|
|
self.tree.addons.Icon:SetImage("icon16/folder_database.png")
|
|
self.tree.addons:SetExpanded(true)
|
|
//
|
|
for tabname, tab in SortedPairs (ParticleListTable.Addons) do
|
|
self.tree.addons[tabname] = self.tree.addons:AddNode(tab.Info.CategoryName)
|
|
self.tree.addons[tabname].Icon:SetImage(tab.Info.Icon)
|
|
|
|
//Create the utilfx list
|
|
if tab.Info.UtilEffects then
|
|
self.tree.addons[tabname].UtilEffects = self.tree.addons[tabname]:AddNode("Scripted Effects")
|
|
self.tree.addons[tabname].UtilEffects.Icon:SetImage("icon16/page_gear.png")
|
|
|
|
self.tree.addons[tabname].UtilEffects.IsPopulated = false
|
|
self.tree.addons[tabname].UtilEffects.DoClick = function()
|
|
if self.tree.addons[tabname].UtilEffects.IsPopulated == true then return end
|
|
|
|
PopulateEffectList(self.tree.addons[tabname].UtilEffects, tab.Info.UtilEffects, tab.Info.EffectOptions)
|
|
|
|
self.tree.addons[tabname].UtilEffects.IsPopulated = true
|
|
self.tree.addons[tabname].UtilEffects:SetExpanded(true)
|
|
end
|
|
end
|
|
|
|
//Create the .pcf lists
|
|
for pcfname, particles in SortedPairs (tab.Particles) do
|
|
local pcftabname = string.StripExtension(pcfname) //just in case having a dot in the key name causes problems
|
|
self.tree.addons[tabname][pcftabname] = self.tree.addons[tabname]:AddNode(pcfname)
|
|
self.tree.addons[tabname][pcftabname].Icon:SetImage("icon16/page.png")
|
|
|
|
self.tree.addons[tabname][pcftabname].IsPopulated = false
|
|
self.tree.addons[tabname][pcftabname].DoClick = function()
|
|
if self.tree.addons[tabname][pcftabname].IsPopulated == true then return end
|
|
|
|
PopulateEffectList(self.tree.addons[tabname][pcftabname], particles, tab.Info.EffectOptions)
|
|
|
|
self.tree.addons[tabname][pcftabname].IsPopulated = true
|
|
self.tree.addons[tabname][pcftabname]:SetExpanded(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
//Favorites
|
|
self.tree.favorites = self.tree:AddNode("Favorites")
|
|
self.tree.favorites.Icon:SetImage("icon16/star.png")
|
|
self.tree.favorites:SetExpanded(true)
|
|
//
|
|
table.insert( ParticleBrowserFavorites.Children, self.tree.favorites ) //Add it to the Favorites table's list of child panels and let it do the rest of the work
|
|
self.tree.favorites.CommandInfo = data.commands //Store the console command info in the panel so the UpdateChildPanel function can access it
|
|
ParticleBrowserFavorites_UpdateChildPanel( self.tree.favorites )
|
|
|
|
|
|
|
|
|
|
self.effectnameentry = vgui.Create( "DTextEntry", self.back )
|
|
self.effectnameentry:SetConVar( data.commands.effectname )
|
|
self.back:AddItem(self.effectnameentry)
|
|
self.effectnameentry:GetParent():DockPadding(5,5,5,10)
|
|
|
|
|
|
|
|
|
|
if data.commands.mode_beam then
|
|
self.beam = vgui.Create("DForm", self.back)
|
|
self.beam.Paint = function()
|
|
derma.SkinHook( "Paint", "CollapsibleCategory", self.beam, self.beam:GetWide(), self.beam:GetTall() )
|
|
surface.SetDrawColor( Color(0,0,0,110) )
|
|
surface.DrawRect( 0, 0, self.beam:GetWide(), self.beam:GetTall() )
|
|
end
|
|
self.beam:Dock(TOP)
|
|
self.back:AddItem(self.beam)
|
|
self.beam:GetParent():DockPadding(5,0,5,0)
|
|
|
|
//Modify the header and tweak things so it doesn't show up when the category is closed.
|
|
self.beam.Header:SetText( "Beam" )
|
|
self.beam.Header:SetImage("icon16/fire_line.png")
|
|
self.beam.Header.DoClick = function() end
|
|
self.beam.PerformLayout = function()
|
|
local us = self.beam //so when we copy this over to another dform we only have to change this one line
|
|
local Padding = us:GetPadding() or 0
|
|
if ( us.Contents ) then
|
|
if ( us:GetExpanded() ) then
|
|
us.Contents:InvalidateLayout( true )
|
|
us.Contents:SetVisible( true )
|
|
else
|
|
us.Contents:SetVisible( false )
|
|
end
|
|
end
|
|
if ( us:GetExpanded() ) then
|
|
us:SizeToChildren( false, true )
|
|
else
|
|
us:SetTall(0) //this is the only real change from the standard DForm:PerformLayout()
|
|
end
|
|
-- Make sure the color of header text is set
|
|
us.Header:ApplySchemeSettings()
|
|
us.animSlide:Run()
|
|
us:UpdateAltLines();
|
|
end
|
|
|
|
self.beam.text = vgui.Create("DLabel", self.beam)
|
|
self.beam.text:SetColor( Color(60,60,60,255) )
|
|
self.beam.text:SetText("This effect attaches to two points.")
|
|
self.beam.text:SetWrap( true )
|
|
self.beam.text:SetAutoStretchVertical( true )
|
|
self.beam.text:Dock(TOP)
|
|
self.beam.text:SizeToContents()
|
|
self.beam:AddItem(self.beam.text)
|
|
self.beam.text:GetParent():DockPadding( 15, 10, 15, 10 )
|
|
end
|
|
|
|
|
|
|
|
|
|
if data.commands.color then
|
|
self.color = vgui.Create("DForm", self.back)
|
|
self.color.Paint = function()
|
|
derma.SkinHook( "Paint", "CollapsibleCategory", self.color, self.color:GetWide(), self.color:GetTall() )
|
|
surface.SetDrawColor( Color(0,0,0,110) )
|
|
surface.DrawRect( 0, 0, self.color:GetWide(), self.color:GetTall() )
|
|
end
|
|
self.color:Dock(TOP)
|
|
self.back:AddItem(self.color)
|
|
self.color:GetParent():DockPadding(5,0,5,0)
|
|
|
|
//Modify the header and tweak things so it doesn't show up when the category is closed.
|
|
self.color.Header:SetText( "Colorable" )
|
|
self.color.Header:SetImage("icon16/fire_rainbow.png")
|
|
self.color.Header.DoClick = function() end
|
|
self.color.PerformLayout = function()
|
|
local us = self.color //so when we copy this over to another dform we only have to change this one line
|
|
local Padding = us:GetPadding() or 0
|
|
if ( us.Contents ) then
|
|
if ( us:GetExpanded() ) then
|
|
us.Contents:InvalidateLayout( true )
|
|
us.Contents:SetVisible( true )
|
|
else
|
|
us.Contents:SetVisible( false )
|
|
end
|
|
end
|
|
if ( us:GetExpanded() ) then
|
|
us:SizeToChildren( false, true )
|
|
else
|
|
us:SetTall(0) //this is the only real change from the standard DForm:PerformLayout()
|
|
end
|
|
-- Make sure the color of header text is set
|
|
us.Header:ApplySchemeSettings()
|
|
us.animSlide:Run()
|
|
us:UpdateAltLines();
|
|
end
|
|
|
|
self.color.text = vgui.Create("DLabel", self.color)
|
|
self.color.text:SetColor( Color(60,60,60,255) )
|
|
self.color.text:SetText("This effect is colorable.")
|
|
self.color.text:SetWrap( true )
|
|
self.color.text:SetAutoStretchVertical( true )
|
|
self.color.text:Dock(TOP)
|
|
self.color.text:SizeToContents()
|
|
self.color:AddItem(self.color.text)
|
|
self.color.text:GetParent():DockPadding( 15, 10, 15, 10 )
|
|
|
|
|
|
self.color.selection = vgui.Create( "CtrlColor", self.color )
|
|
self.color.selection:SetLabel( "" )
|
|
self.color.selection:SetConVarR( data.commands.color .. "_r" )
|
|
self.color.selection:SetConVarG( data.commands.color .. "_g" )
|
|
self.color.selection:SetConVarB( data.commands.color .. "_b" )
|
|
self.color.selection:SetConVarA( nil )
|
|
self.color.selection:Dock(TOP)
|
|
self.color:AddItem(self.color.selection)
|
|
self.color.selection:GetParent():DockPadding( 10, 0, 10, 10 )
|
|
end
|
|
|
|
|
|
|
|
|
|
if data.commands.utileffect then
|
|
self.utilfx = vgui.Create("DForm", self.back)
|
|
self.utilfx.Paint = function()
|
|
derma.SkinHook( "Paint", "CollapsibleCategory", self.utilfx, self.utilfx:GetWide(), self.utilfx:GetTall() )
|
|
surface.SetDrawColor( Color(0,0,0,110) )
|
|
surface.DrawRect( 0, 0, self.utilfx:GetWide(), self.utilfx:GetTall() )
|
|
end
|
|
self.utilfx:Dock(TOP)
|
|
self.back:AddItem(self.utilfx)
|
|
self.utilfx:GetParent():DockPadding(5,0,5,0)
|
|
|
|
//Modify the header and tweak things so it doesn't show up when the category is closed.
|
|
self.utilfx.Header:SetText( "Scripted Effect" )
|
|
self.utilfx.Header:SetImage("icon16/cog.png")
|
|
self.utilfx.Header.DoClick = function() end
|
|
self.utilfx.PerformLayout = function()
|
|
local us = self.utilfx //so when we copy this over to another dform we only have to change this one line
|
|
local Padding = us:GetPadding() or 0
|
|
if ( us.Contents ) then
|
|
if ( us:GetExpanded() ) then
|
|
us.Contents:InvalidateLayout( true )
|
|
us.Contents:SetVisible( true )
|
|
else
|
|
us.Contents:SetVisible( false )
|
|
end
|
|
end
|
|
if ( us:GetExpanded() ) then
|
|
us:SizeToChildren( false, true )
|
|
else
|
|
us:SetTall(0) //this is the only real change from the standard DForm:PerformLayout()
|
|
end
|
|
-- Make sure the color of header text is set
|
|
us.Header:ApplySchemeSettings()
|
|
us.animSlide:Run()
|
|
us:UpdateAltLines();
|
|
end
|
|
|
|
self.utilfx.text = vgui.Create("DLabel", self.utilfx)
|
|
self.utilfx.text:SetColor( Color(60,60,60,255) )
|
|
self.utilfx.text:SetText("These options can be used to modify certain scripted effects in different ways depending on the effect being used.")
|
|
self.utilfx.text:SetWrap( true )
|
|
self.utilfx.text:SetAutoStretchVertical( true )
|
|
self.utilfx.text:Dock(TOP)
|
|
self.utilfx.text:SizeToContents()
|
|
self.utilfx:AddItem(self.utilfx.text)
|
|
self.utilfx.text:GetParent():DockPadding( 15, 10, 15, 5 )
|
|
|
|
|
|
self.utilfx.slider1 = vgui.Create( "DNumSlider", self.utilfx )
|
|
self.utilfx.slider1:SetText( "Util.Effect Scale" )
|
|
self.utilfx.slider1:SetMinMax(0.2, 10)
|
|
self.utilfx.slider1:SetDecimals(2)
|
|
self.utilfx.slider1:SetConVar( data.commands.utileffect .. "_scale" )
|
|
self.utilfx.slider1:SetHeight(15)
|
|
self.utilfx.slider1:SizeToContents()
|
|
self.utilfx.slider1:SetDark(true)
|
|
self.utilfx:AddItem(self.utilfx.slider1)
|
|
|
|
self.utilfx.slider2 = vgui.Create( "DNumSlider", self.utilfx )
|
|
self.utilfx.slider2:SetText( "Util.Effect Magnitude" )
|
|
self.utilfx.slider2:SetMinMax(1, 10)
|
|
self.utilfx.slider2:SetDecimals(2)
|
|
self.utilfx.slider2:SetConVar( data.commands.utileffect .. "_magnitude" )
|
|
self.utilfx.slider2:SetHeight(15)
|
|
self.utilfx.slider2:SizeToContents()
|
|
self.utilfx.slider2:SetDark(true)
|
|
self.utilfx:AddItem(self.utilfx.slider2)
|
|
|
|
self.utilfx.slider3 = vgui.Create( "DNumSlider", self.utilfx )
|
|
self.utilfx.slider3:SetText( "Util.Effect Radius" )
|
|
self.utilfx.slider3:SetMinMax(10, 1000)
|
|
self.utilfx.slider3:SetDecimals(2)
|
|
self.utilfx.slider3:SetConVar( data.commands.utileffect .. "_radius" )
|
|
self.utilfx.slider3:SetHeight(15)
|
|
self.utilfx.slider3:SizeToContents()
|
|
self.utilfx.slider3:SetDark(true)
|
|
self.utilfx:AddItem(self.utilfx.slider3)
|
|
end
|
|
|
|
|
|
|
|
|
|
self.back.Think = function()
|
|
if self.beam then
|
|
if GetConVarNumber( data.commands.mode_beam ) > 0 then
|
|
//expand it
|
|
if self.beam:GetExpanded() == false then self.beam:Toggle() end
|
|
else
|
|
//contract it
|
|
if self.beam:GetExpanded() == true then self.beam:Toggle() end
|
|
self.beam:GetParent():SetTall(self.beam:GetTall())
|
|
end
|
|
end
|
|
if self.color then
|
|
if GetConVarNumber( data.commands.color .. "_enabled" ) > 0 then
|
|
//expand it
|
|
if self.color:GetExpanded() == false then self.color:Toggle() end
|
|
else
|
|
//contract it
|
|
if self.color:GetExpanded() == true then self.color:Toggle() end
|
|
self.color:GetParent():SetTall(self.color:GetTall())
|
|
end
|
|
end
|
|
if self.utilfx then
|
|
if string.StartWith( GetConVarString(data.commands.effectname), "!UTILEFFECT!" ) then
|
|
//expand it
|
|
if self.utilfx:GetExpanded() == false then self.utilfx:Toggle() end
|
|
else
|
|
//contract it
|
|
if self.utilfx:GetExpanded() == true then self.utilfx:Toggle() end
|
|
self.utilfx:GetParent():SetTall(self.utilfx:GetTall())
|
|
end
|
|
end
|
|
|
|
|
|
if data.commands.enabled then
|
|
if GetConVarNumber( data.commands.enabled ) > 0 then
|
|
//expand it
|
|
if self.back:GetExpanded() == false then self.back:Toggle() end
|
|
else
|
|
//contract it
|
|
if self.back:GetExpanded() == true then self.back:Toggle() end
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Favorites - this table is global too because this is all copied over from the standard Particle Browser, even though I don't suspect we'll ever have more than one of these
|
|
ParticleBrowserTracerFavorites = {
|
|
Effects = {}, //effects in the favorites list
|
|
Children = {}, //all DTreeNode panels that are using this favorites list
|
|
}
|
|
|
|
local parctrltracerfavs_str = file.Read("particlecontrol_favorites_tracer.txt","DATA")
|
|
if parctrltracerfavs_str then ParticleBrowserTracerFavorites.Effects = util.JSONToTable(parctrltracerfavs_str) end
|
|
|
|
|
|
function ParticleBrowserTracerFavorites_UpdateEffect( effectdisplay, effectoptions )
|
|
|
|
if effectoptions then
|
|
//We're adding the effect
|
|
ParticleBrowserTracerFavorites.Effects[effectdisplay] = effectoptions
|
|
else
|
|
//We're removing the effect
|
|
ParticleBrowserTracerFavorites.Effects[effectdisplay] = nil
|
|
end
|
|
|
|
for _, panel in pairs (ParticleBrowserTracerFavorites.Children) do
|
|
if panel then
|
|
ParticleBrowserTracerFavorites_UpdateChildPanel( panel )
|
|
end
|
|
end
|
|
|
|
file.Write( "particlecontrol_favorites_tracer.txt", util.TableToJSON(ParticleBrowserTracerFavorites.Effects, true) )
|
|
|
|
end
|
|
|
|
|
|
function ParticleBrowserTracerFavorites_UpdateChildPanel( panel )
|
|
|
|
if !panel then return end
|
|
|
|
if panel.FavoriteNodes then
|
|
//Remove all of the nodes from the panel
|
|
for k, node in pairs (panel.FavoriteNodes) do
|
|
node:Remove()
|
|
panel.FavoriteNodes[k] = nil
|
|
end
|
|
else
|
|
panel.FavoriteNodes = {}
|
|
end
|
|
|
|
for effectdisplay, effectoptions in SortedPairs (ParticleBrowserTracerFavorites.Effects) do
|
|
local effect = effectoptions["InternalName"]
|
|
|
|
panel.FavoriteNodes[effect] = panel:AddNode(effectdisplay)
|
|
|
|
panel.FavoriteNodes[effect].EffectOptions = {}
|
|
if effectoptions["Colorable"] then
|
|
panel.FavoriteNodes[effect].EffectOptions["Colorable"] = true
|
|
end
|
|
if effectoptions["ColorOutOfOne"] then
|
|
panel.FavoriteNodes[effect].EffectOptions["ColorOutOfOne"] = true
|
|
end
|
|
|
|
//Don't use the icons for features we're not using
|
|
local coloricon = ( (panel.CommandInfo.color) and (panel.FavoriteNodes[effect].EffectOptions["Colorable"] == true) )
|
|
//Set the effect icon:
|
|
if coloricon then
|
|
panel.FavoriteNodes[effect].Icon:SetImage("icon16/fire_line_rainbow.png")
|
|
else
|
|
panel.FavoriteNodes[effect].Icon:SetImage("icon16/fire_line.png")
|
|
end
|
|
|
|
panel.FavoriteNodes[effect].DoClick = function()
|
|
RunConsoleCommand( panel.CommandInfo.effectname, effect )
|
|
|
|
if panel.CommandInfo.color then
|
|
if panel.FavoriteNodes[effect].EffectOptions["Colorable"] then
|
|
RunConsoleCommand( panel.CommandInfo.color .. "_enabled", "1" )
|
|
else
|
|
RunConsoleCommand( panel.CommandInfo.color .. "_enabled", "0" )
|
|
end
|
|
|
|
if panel.FavoriteNodes[effect].EffectOptions["ColorOutOfOne"] then
|
|
RunConsoleCommand( panel.CommandInfo.color .. "_outofone", "1" )
|
|
else
|
|
RunConsoleCommand( panel.CommandInfo.color .. "_outofone", "0" )
|
|
end
|
|
end
|
|
end
|
|
|
|
panel.FavoriteNodes[effect].DoRightClick = function()
|
|
//We only need the remove option here, since it's already in the favorites list
|
|
local menu = DermaMenu()
|
|
|
|
local option = menu:AddOption( "Un-favorite \'\'" .. effectdisplay .. "\'\'", function()
|
|
ParticleBrowserTracerFavorites_UpdateEffect( effectdisplay ) //calling this function with no second arg tells it to remove this effect from the list
|
|
end )
|
|
option:SetImage("icon16/delete.png")
|
|
|
|
menu:Open()
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function AddParticleBrowserTracer(panel,data)
|
|
|
|
local self = {}
|
|
|
|
//Data table contents:
|
|
//{
|
|
//name = "Effect" (name to show at the top of the panel)
|
|
//commands = (table of concommands that the panel uses)
|
|
// {
|
|
// effectname = "particlecontrol_effectname"
|
|
// color = "particlecontrol_color" (optional, assumes there are cvars derived from this name (X_enabled, X_r, X_g, X_b, X_outofone) )
|
|
// }
|
|
//}
|
|
|
|
self.back = vgui.Create("DForm", panel)
|
|
self.back:SetLabel(data.name)
|
|
self.back.Paint = function()
|
|
derma.SkinHook( "Paint", "CollapsibleCategory", self.back, self.back:GetWide(), self.back:GetTall() )
|
|
surface.SetDrawColor( Color(0,0,0,70) )
|
|
surface.DrawRect( 0, 0, self.back:GetWide(), self.back:GetTall() )
|
|
end
|
|
self.back.Header:SetImage("icon16/fire.png")
|
|
self.back.Header.DoClick = function() end
|
|
panel:AddPanel(self.back)
|
|
|
|
|
|
|
|
|
|
self.tree = vgui.Create("DTree", self.back)
|
|
self.tree:SetHeight(400)
|
|
self.back:AddItem(self.tree)
|
|
self.tree:GetParent():DockPadding(5,5,5,0)
|
|
|
|
local function PopulateEffectList(parent, effectstab, effectoptions)
|
|
for k, v in SortedPairs (effectstab) do
|
|
local effect = k
|
|
local effectdisplay = k
|
|
//if v is another string instead of just a filler "true" value, then that means k is the display name and v is the internal name
|
|
if isstring(v) then
|
|
effect = v
|
|
end
|
|
|
|
parent[effect] = parent:AddNode(effectdisplay)
|
|
|
|
parent[effect].EffectOptions = {}
|
|
if effectoptions["Color1"] and effectoptions["Color1"][effect] then
|
|
parent[effect].EffectOptions["Colorable"] = true
|
|
parent[effect].EffectOptions["ColorOutOfOne"] = true
|
|
end
|
|
if effectoptions["Color255"] and effectoptions["Color255"][effect] then
|
|
parent[effect].EffectOptions["Colorable"] = true
|
|
parent[effect].EffectOptions["ColorOutOfOne"] = false
|
|
end
|
|
|
|
//Don't use the icons for features we're not using
|
|
local coloricon = ( (data.commands.color) and (parent[effect].EffectOptions["Colorable"] == true) )
|
|
//Set the effect icon:
|
|
if coloricon then
|
|
parent[effect].Icon:SetImage("icon16/fire_line_rainbow.png")
|
|
else
|
|
parent[effect].Icon:SetImage("icon16/fire_line.png")
|
|
end
|
|
|
|
//Left Click: Select the effect by setting its concommands
|
|
parent[effect].DoClick = function()
|
|
RunConsoleCommand( data.commands.effectname, effect )
|
|
|
|
if data.commands.color then
|
|
if parent[effect].EffectOptions["Colorable"] then
|
|
RunConsoleCommand( data.commands.color .. "_enabled", "1" )
|
|
else
|
|
RunConsoleCommand( data.commands.color .. "_enabled", "0" )
|
|
end
|
|
|
|
if parent[effect].EffectOptions["ColorOutOfOne"] then
|
|
RunConsoleCommand( data.commands.color .. "_outofone", "1" )
|
|
else
|
|
RunConsoleCommand( data.commands.color .. "_outofone", "0" )
|
|
end
|
|
end
|
|
end
|
|
|
|
//Right Click: Display an option to add/remove the effect from favorites
|
|
parent[effect].DoRightClick = function()
|
|
local menu = DermaMenu()
|
|
|
|
if !ParticleBrowserTracerFavorites.Effects[effectdisplay] then
|
|
local option = menu:AddOption( "Favorite \'\'" .. effectdisplay .. "\'\'", function()
|
|
ParticleBrowserTracerFavorites_UpdateEffect( effectdisplay, {
|
|
["InternalName"] = effect,
|
|
["Colorable"] = tobool(parent[effect].EffectOptions["Colorable"]),
|
|
["ColorOutOfOne"] = tobool(parent[effect].EffectOptions["ColorOutOfOne"]),
|
|
} )
|
|
end )
|
|
option:SetImage("icon16/add.png")
|
|
else
|
|
local option = menu:AddOption( "Un-favorite \'\'" .. effectdisplay .. "\'\'", function()
|
|
ParticleBrowserTracerFavorites_UpdateEffect( effectdisplay ) //calling this function with no second arg tells it to remove this effect from the list
|
|
end )
|
|
option:SetImage("icon16/delete.png")
|
|
end
|
|
|
|
menu:Open()
|
|
end
|
|
end
|
|
end
|
|
|
|
//Games
|
|
self.tree.games = self.tree:AddNode("Games")
|
|
self.tree.games.Icon:SetImage("icon16/folder_database.png")
|
|
self.tree.games:SetExpanded(true)
|
|
//
|
|
for tabname, tab in SortedPairs (ParticleListTable.Games) do
|
|
if tab.Info.EffectOptions.Tracers then
|
|
self.tree.games[tabname] = self.tree.games:AddNode(tab.Info.CategoryName)
|
|
self.tree.games[tabname].Icon:SetImage(tab.Info.Icon)
|
|
|
|
//Create the utilfx list
|
|
if tab.Info.UtilEffects then
|
|
local tracerlist = {}
|
|
for k, v in pairs (tab.Info.UtilEffects) do
|
|
//in a utileffect table, the effect name is stored in the value
|
|
if tab.Info.EffectOptions.Tracers[v] then tracerlist[k] = v end
|
|
end
|
|
if table.Count(tracerlist) > 0 then
|
|
self.tree.games[tabname].UtilEffects = self.tree.games[tabname]:AddNode("Scripted Effects")
|
|
self.tree.games[tabname].UtilEffects.Icon:SetImage("icon16/page_gear.png")
|
|
|
|
self.tree.games[tabname].UtilEffects.IsPopulated = false
|
|
self.tree.games[tabname].UtilEffects.DoClick = function()
|
|
if self.tree.games[tabname].UtilEffects.IsPopulated == true then return end
|
|
|
|
PopulateEffectList(self.tree.games[tabname].UtilEffects, tracerlist, tab.Info.EffectOptions)
|
|
|
|
self.tree.games[tabname].UtilEffects.IsPopulated = true
|
|
self.tree.games[tabname].UtilEffects:SetExpanded(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
//Create the .pcf lists
|
|
for pcfname, particles in SortedPairs (tab.Particles) do
|
|
local tracerlist = {}
|
|
for k, v in pairs (particles) do
|
|
//in a particle table, the effect name is stored in the key
|
|
if tab.Info.EffectOptions.Tracers[k] then tracerlist[k] = v end
|
|
end
|
|
if table.Count(tracerlist) > 0 then
|
|
local pcftabname = string.StripExtension(pcfname) //just in case having a dot in the key name causes problems
|
|
self.tree.games[tabname][pcftabname] = self.tree.games[tabname]:AddNode(pcfname)
|
|
self.tree.games[tabname][pcftabname].Icon:SetImage("icon16/page.png")
|
|
|
|
self.tree.games[tabname][pcftabname].IsPopulated = false
|
|
self.tree.games[tabname][pcftabname].DoClick = function()
|
|
if self.tree.games[tabname][pcftabname].IsPopulated == true then return end
|
|
|
|
PopulateEffectList(self.tree.games[tabname][pcftabname], tracerlist, tab.Info.EffectOptions)
|
|
|
|
self.tree.games[tabname][pcftabname].IsPopulated = true
|
|
self.tree.games[tabname][pcftabname]:SetExpanded(true)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
//Addons
|
|
self.tree.addons = self.tree:AddNode("Addons")
|
|
self.tree.addons.Icon:SetImage("icon16/folder_database.png")
|
|
self.tree.addons:SetExpanded(true)
|
|
//
|
|
for tabname, tab in SortedPairs (ParticleListTable.Addons) do
|
|
if tab.Info.EffectOptions.Tracers then
|
|
self.tree.addons[tabname] = self.tree.addons:AddNode(tab.Info.CategoryName)
|
|
self.tree.addons[tabname].Icon:SetImage(tab.Info.Icon)
|
|
|
|
//Create the utilfx list
|
|
if tab.Info.UtilEffects then
|
|
local tracerlist = {}
|
|
for k, v in pairs (tab.Info.UtilEffects) do
|
|
//in a utileffect table, the effect name is stored in the value
|
|
if tab.Info.EffectOptions.Tracers[v] then tracerlist[k] = v end
|
|
end
|
|
if table.Count(tracerlist) > 0 then
|
|
self.tree.addons[tabname].UtilEffects = self.tree.addons[tabname]:AddNode("Scripted Effects")
|
|
self.tree.addons[tabname].UtilEffects.Icon:SetImage("icon16/page_gear.png")
|
|
|
|
self.tree.addons[tabname].UtilEffects.IsPopulated = false
|
|
self.tree.addons[tabname].UtilEffects.DoClick = function()
|
|
if self.tree.addons[tabname].UtilEffects.IsPopulated == true then return end
|
|
|
|
PopulateEffectList(self.tree.addons[tabname].UtilEffects, tracerlist, tab.Info.EffectOptions)
|
|
|
|
self.tree.addons[tabname].UtilEffects.IsPopulated = true
|
|
self.tree.addons[tabname].UtilEffects:SetExpanded(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
//Create the .pcf lists
|
|
for pcfname, particles in SortedPairs (tab.Particles) do
|
|
local tracerlist = {}
|
|
for k, v in pairs (particles) do
|
|
//in a particle table, the effect name is stored in the key
|
|
if tab.Info.EffectOptions.Tracers[k] then tracerlist[k] = v end
|
|
end
|
|
if table.Count(tracerlist) > 0 then
|
|
local pcftabname = string.StripExtension(pcfname) //just in case having a dot in the key name causes problems
|
|
self.tree.addons[tabname][pcftabname] = self.tree.addons[tabname]:AddNode(pcfname)
|
|
self.tree.addons[tabname][pcftabname].Icon:SetImage("icon16/page.png")
|
|
|
|
self.tree.addons[tabname][pcftabname].IsPopulated = false
|
|
self.tree.addons[tabname][pcftabname].DoClick = function()
|
|
if self.tree.addons[tabname][pcftabname].IsPopulated == true then return end
|
|
|
|
PopulateEffectList(self.tree.addons[tabname][pcftabname], tracerlist, tab.Info.EffectOptions)
|
|
|
|
self.tree.addons[tabname][pcftabname].IsPopulated = true
|
|
self.tree.addons[tabname][pcftabname]:SetExpanded(true)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
//Favorites
|
|
self.tree.favorites = self.tree:AddNode("Favorites (Tracers)")
|
|
self.tree.favorites.Icon:SetImage("icon16/star.png")
|
|
self.tree.favorites:SetExpanded(true)
|
|
//
|
|
table.insert( ParticleBrowserTracerFavorites.Children, self.tree.favorites ) //Add it to the Favorites table's list of child panels and let it do the rest of the work
|
|
self.tree.favorites.CommandInfo = data.commands //Store the console command info in the panel so the UpdateChildPanel function can access it
|
|
ParticleBrowserTracerFavorites_UpdateChildPanel( self.tree.favorites )
|
|
|
|
|
|
|
|
|
|
self.effectnameentry = vgui.Create( "DTextEntry", self.back )
|
|
self.effectnameentry:SetConVar( data.commands.effectname )
|
|
self.back:AddItem(self.effectnameentry)
|
|
self.effectnameentry:GetParent():DockPadding(5,5,5,10)
|
|
|
|
|
|
|
|
|
|
if data.commands.color then
|
|
self.color = vgui.Create("DForm", self.back)
|
|
self.color.Paint = function()
|
|
derma.SkinHook( "Paint", "CollapsibleCategory", self.color, self.color:GetWide(), self.color:GetTall() )
|
|
surface.SetDrawColor( Color(0,0,0,110) )
|
|
surface.DrawRect( 0, 0, self.color:GetWide(), self.color:GetTall() )
|
|
end
|
|
self.color:Dock(TOP)
|
|
self.back:AddItem(self.color)
|
|
self.color:GetParent():DockPadding(5,0,5,0)
|
|
|
|
//Modify the header and tweak things so it doesn't show up when the category is closed.
|
|
self.color.Header:SetText( "Colorable" )
|
|
self.color.Header:SetImage("icon16/fire_rainbow.png")
|
|
self.color.Header.DoClick = function() end
|
|
self.color.PerformLayout = function()
|
|
local us = self.color //so when we copy this over to another dform we only have to change this one line
|
|
local Padding = us:GetPadding() or 0
|
|
if ( us.Contents ) then
|
|
if ( us:GetExpanded() ) then
|
|
us.Contents:InvalidateLayout( true )
|
|
us.Contents:SetVisible( true )
|
|
else
|
|
us.Contents:SetVisible( false )
|
|
end
|
|
end
|
|
if ( us:GetExpanded() ) then
|
|
us:SizeToChildren( false, true )
|
|
else
|
|
us:SetTall(0) //this is the only real change from the standard DForm:PerformLayout()
|
|
end
|
|
-- Make sure the color of header text is set
|
|
us.Header:ApplySchemeSettings()
|
|
us.animSlide:Run()
|
|
us:UpdateAltLines();
|
|
end
|
|
|
|
self.color.text = vgui.Create("DLabel", self.color)
|
|
self.color.text:SetColor( Color(60,60,60,255) )
|
|
self.color.text:SetText("This effect is colorable.")
|
|
self.color.text:SetWrap( true )
|
|
self.color.text:SetAutoStretchVertical( true )
|
|
self.color.text:Dock(TOP)
|
|
self.color.text:SizeToContents()
|
|
self.color:AddItem(self.color.text)
|
|
self.color.text:GetParent():DockPadding( 15, 10, 15, 10 )
|
|
|
|
|
|
self.color.selection = vgui.Create( "CtrlColor", self.color )
|
|
self.color.selection:SetLabel( "" )
|
|
self.color.selection:SetConVarR( data.commands.color .. "_r" )
|
|
self.color.selection:SetConVarG( data.commands.color .. "_g" )
|
|
self.color.selection:SetConVarB( data.commands.color .. "_b" )
|
|
self.color.selection:SetConVarA( nil )
|
|
self.color.selection:Dock(TOP)
|
|
self.color:AddItem(self.color.selection)
|
|
self.color.selection:GetParent():DockPadding( 10, 0, 10, 10 )
|
|
end
|
|
|
|
|
|
|
|
|
|
self.back.Think = function()
|
|
if self.color then
|
|
if GetConVarNumber( data.commands.color .. "_enabled" ) > 0 then
|
|
//expand it
|
|
if self.color:GetExpanded() == false then self.color:Toggle() end
|
|
else
|
|
//contract it
|
|
if self.color:GetExpanded() == true then self.color:Toggle() end
|
|
self.color:GetParent():SetTall(self.color:GetTall())
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
end |