mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
Upload
This commit is contained in:
251
gamemodes/sandbox/gamemode/spawnmenu/contextmenu.lua
Normal file
251
gamemodes/sandbox/gamemode/spawnmenu/contextmenu.lua
Normal file
@@ -0,0 +1,251 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_bHangOpen", "HangOpen" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
--
|
||||
-- This makes it so that when you're hovering over this panel
|
||||
-- you can `click` on the world. Your viewmodel will aim etc.
|
||||
--
|
||||
self:SetWorldClicker( true )
|
||||
|
||||
self.Canvas = vgui.Create( "DCategoryList", self )
|
||||
self.m_bHangOpen = false
|
||||
|
||||
self:Dock( FILL )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Open()
|
||||
|
||||
self:SetHangOpen( false )
|
||||
|
||||
-- If the spawn menu is open, try to close it..
|
||||
if ( IsValid( g_SpawnMenu ) && g_SpawnMenu:IsVisible() ) then
|
||||
g_SpawnMenu:Close( true )
|
||||
end
|
||||
|
||||
if ( self:IsVisible() ) then return end
|
||||
|
||||
CloseDermaMenus()
|
||||
|
||||
self:MakePopup()
|
||||
self:SetVisible( true )
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
self:SetMouseInputEnabled( true )
|
||||
|
||||
RestoreCursorPosition()
|
||||
|
||||
local bShouldShow = hook.Run( "ContextMenuShowTool" )
|
||||
local bShow = bShouldShow == nil or bShouldShow
|
||||
|
||||
-- Set up the active panel..
|
||||
if ( bShow && IsValid( spawnmenu.ActiveControlPanel() ) ) then
|
||||
|
||||
self.OldParent = spawnmenu.ActiveControlPanel():GetParent()
|
||||
self.OldPosX, self.OldPosY = spawnmenu.ActiveControlPanel():GetPos()
|
||||
spawnmenu.ActiveControlPanel():SetParent( self )
|
||||
self.Canvas:Clear()
|
||||
self.Canvas:AddItem( spawnmenu.ActiveControlPanel() )
|
||||
self.Canvas:Rebuild()
|
||||
self.Canvas:SetVisible( true )
|
||||
|
||||
else
|
||||
|
||||
self.Canvas:SetVisible( false )
|
||||
|
||||
end
|
||||
|
||||
self:InvalidateLayout( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Close( bSkipAnim )
|
||||
|
||||
if ( self:GetHangOpen() ) then
|
||||
self:SetHangOpen( false )
|
||||
return
|
||||
end
|
||||
|
||||
RememberCursorPosition()
|
||||
|
||||
CloseDermaMenus()
|
||||
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
self:SetMouseInputEnabled( false )
|
||||
|
||||
self:SetAlpha( 255 )
|
||||
self:SetVisible( false )
|
||||
self:RestoreControlPanel()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
if ( IsValid( spawnmenu.ActiveControlPanel() ) ) then
|
||||
|
||||
spawnmenu.ActiveControlPanel():InvalidateLayout( true )
|
||||
|
||||
local Tall = math.min( spawnmenu.ActiveControlPanel():GetTall() + 10, ScrH() * 0.8 )
|
||||
if ( self.Canvas:GetTall() != Tall ) then self.Canvas:SetTall( Tall ) end
|
||||
if ( self.Canvas:GetWide() != 320 ) then self.Canvas:SetWide( 320 ) end
|
||||
|
||||
self.Canvas:SetPos( ScrW() - self.Canvas:GetWide() - 50, ScrH() - 50 - Tall )
|
||||
self.Canvas:InvalidateLayout( true )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:StartKeyFocus( pPanel )
|
||||
|
||||
self:SetKeyboardInputEnabled( true )
|
||||
self:SetHangOpen( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:EndKeyFocus( pPanel )
|
||||
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:RestoreControlPanel()
|
||||
|
||||
-- Restore the active panel
|
||||
if ( !spawnmenu.ActiveControlPanel() ) then return end
|
||||
if ( !self.OldParent ) then return end
|
||||
|
||||
spawnmenu.ActiveControlPanel():SetParent( self.OldParent )
|
||||
spawnmenu.ActiveControlPanel():SetPos( self.OldPosX, self.OldPosY )
|
||||
|
||||
self.OldParent = nil
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Note here: EditablePanel is important! Child panels won't be able to get
|
||||
-- keyboard input if it's a DPanel or a Panel. You need to either have an EditablePanel
|
||||
-- or a DFrame (which is derived from EditablePanel) as your first panel attached to the system.
|
||||
--
|
||||
vgui.Register( "ContextMenu", PANEL, "EditablePanel" )
|
||||
|
||||
function CreateContextMenu()
|
||||
|
||||
if ( !hook.Run( "ContextMenuEnabled" ) ) then return end
|
||||
|
||||
if ( IsValid( g_ContextMenu ) ) then
|
||||
g_ContextMenu:Remove()
|
||||
g_ContextMenu = nil
|
||||
end
|
||||
|
||||
g_ContextMenu = vgui.Create( "ContextMenu" )
|
||||
|
||||
if ( !IsValid( g_ContextMenu ) ) then return end
|
||||
|
||||
g_ContextMenu:SetVisible( false )
|
||||
|
||||
--
|
||||
-- We're blocking clicks to the world - but we don't want to
|
||||
-- so feed clicks to the proper functions..
|
||||
--
|
||||
g_ContextMenu.OnMousePressed = function( p, code )
|
||||
hook.Run( "GUIMousePressed", code, gui.ScreenToVector( input.GetCursorPos() ) )
|
||||
end
|
||||
g_ContextMenu.OnMouseReleased = function( p, code )
|
||||
hook.Run( "GUIMouseReleased", code, gui.ScreenToVector( input.GetCursorPos() ) )
|
||||
end
|
||||
|
||||
hook.Run( "ContextMenuCreated", g_ContextMenu )
|
||||
|
||||
local IconLayout = g_ContextMenu:Add( "DIconLayout" )
|
||||
IconLayout:SetBorder( 8 )
|
||||
IconLayout:SetSpaceX( 8 )
|
||||
IconLayout:SetSpaceY( 8 )
|
||||
IconLayout:SetLayoutDir( LEFT )
|
||||
IconLayout:SetWorldClicker( true )
|
||||
IconLayout:SetStretchWidth( true )
|
||||
IconLayout:SetStretchHeight( false ) -- No infinite re-layouts
|
||||
IconLayout:Dock( LEFT )
|
||||
|
||||
-- This overrides DIconLayout's OnMousePressed (which is inherited from DPanel), but we don't care about that in this case
|
||||
IconLayout.OnMousePressed = function( s, ... ) s:GetParent():OnMousePressed( ... ) end
|
||||
|
||||
for k, v in pairs( list.Get( "DesktopWindows" ) ) do
|
||||
|
||||
local icon = IconLayout:Add( "DButton" )
|
||||
icon:SetText( "" )
|
||||
icon:SetSize( 80, 82 )
|
||||
icon.Paint = function() end
|
||||
|
||||
local image = icon:Add( "DImage" )
|
||||
image:SetImage( v.icon )
|
||||
image:SetSize( 64, 64 )
|
||||
image:Dock( TOP )
|
||||
image:DockMargin( 8, 0, 8, 0 )
|
||||
|
||||
local label = icon:Add( "DLabel" )
|
||||
label:Dock( BOTTOM )
|
||||
label:SetText( v.title )
|
||||
label:SetContentAlignment( 5 )
|
||||
label:SetTextColor( color_white )
|
||||
label:SetExpensiveShadow( 1, Color( 0, 0, 0, 200 ) )
|
||||
|
||||
icon.DoClick = function()
|
||||
|
||||
--
|
||||
-- v might have changed using autorefresh so grab it again
|
||||
--
|
||||
local newv = list.Get( "DesktopWindows" )[ k ]
|
||||
|
||||
if ( v.onewindow and IsValid( icon.Window ) ) then
|
||||
icon.Window:Center()
|
||||
return
|
||||
end
|
||||
|
||||
-- Make the window
|
||||
icon.Window = g_ContextMenu:Add( "DFrame" )
|
||||
icon.Window:SetSize( newv.width, newv.height )
|
||||
icon.Window:SetTitle( newv.title )
|
||||
icon.Window:Center()
|
||||
|
||||
newv.init( icon, icon.Window )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function GM:OnContextMenuOpen()
|
||||
|
||||
-- Let the gamemode decide whether we should open or not..
|
||||
if ( !hook.Call( "ContextMenuOpen", self ) ) then return end
|
||||
|
||||
if ( IsValid( g_ContextMenu ) && !g_ContextMenu:IsVisible() ) then
|
||||
g_ContextMenu:Open()
|
||||
menubar.ParentTo( g_ContextMenu )
|
||||
end
|
||||
|
||||
hook.Call( "ContextMenuOpened", self )
|
||||
|
||||
end
|
||||
|
||||
function GM:OnContextMenuClose()
|
||||
|
||||
if ( IsValid( g_ContextMenu ) ) then g_ContextMenu:Close() end
|
||||
hook.Call( "ContextMenuClosed", self )
|
||||
|
||||
end
|
||||
443
gamemodes/sandbox/gamemode/spawnmenu/controlpanel.lua
Normal file
443
gamemodes/sandbox/gamemode/spawnmenu/controlpanel.lua
Normal file
@@ -0,0 +1,443 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- Note: This is only really here as a layer between the spawnmenu
|
||||
-- and the DForm Derma control. You shouldn't ever really be
|
||||
-- calling AddControl. If you're writing new code - don't call
|
||||
-- AddControl!! Add stuff directly using the DForm member functions!
|
||||
--
|
||||
|
||||
include( "controls/manifest.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_bInitialized", "Initialized" )
|
||||
|
||||
function PANEL:Init()
|
||||
self:SetInitialized( false )
|
||||
end
|
||||
|
||||
function PANEL:ClearControls()
|
||||
self:Clear()
|
||||
end
|
||||
|
||||
function PANEL:GetEmbeddedPanel()
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddPanel( pnl )
|
||||
|
||||
self:AddItem( pnl, nil )
|
||||
self:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:MatSelect( strConVar, tblOptions, bAutoStretch, iWidth, iHeight )
|
||||
|
||||
local MatSelect = vgui.Create( "MatSelect", self )
|
||||
Derma_Hook( MatSelect.List, "Paint", "Paint", "Panel" )
|
||||
|
||||
MatSelect:SetConVar( strConVar )
|
||||
|
||||
if ( bAutoStretch != nil ) then MatSelect:SetAutoHeight( bAutoStretch ) end
|
||||
if ( iWidth != nil ) then MatSelect:SetItemWidth( iWidth ) end
|
||||
if ( iHeight != nil ) then MatSelect:SetItemHeight( iHeight ) end
|
||||
|
||||
if ( tblOptions != nil ) then
|
||||
for k, v in pairs( tblOptions ) do
|
||||
local nam = isnumber( k ) and v or k
|
||||
MatSelect:AddMaterial( nam, v )
|
||||
end
|
||||
end
|
||||
|
||||
self:AddPanel( MatSelect )
|
||||
return MatSelect
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ToolPresets( group, cvarlist )
|
||||
|
||||
local preset = vgui.Create( "ControlPresets", self )
|
||||
|
||||
preset:SetPreset( group )
|
||||
preset:AddOption( "#preset.default", cvarlist )
|
||||
|
||||
for k, v in pairs( cvarlist ) do
|
||||
preset:AddConVar( k )
|
||||
end
|
||||
|
||||
self:AddItem( preset )
|
||||
|
||||
return preset
|
||||
|
||||
end
|
||||
|
||||
function PANEL:KeyBinder( label1, convar1, label2, convar2 )
|
||||
|
||||
local binder = vgui.Create( "CtrlNumPad", self )
|
||||
|
||||
binder:SetLabel1( label1 )
|
||||
binder:SetConVar1( convar1 )
|
||||
|
||||
if ( label2 != nil and convar2 != nil ) then
|
||||
binder:SetLabel2( label2 )
|
||||
binder:SetConVar2( convar2 )
|
||||
end
|
||||
|
||||
self:AddPanel( binder )
|
||||
|
||||
return binder
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ColorPicker( label, convarR, convarG, convarB, convarA )
|
||||
|
||||
local color = vgui.Create( "CtrlColor", self )
|
||||
|
||||
color:Dock( TOP )
|
||||
color:SetLabel( label )
|
||||
|
||||
color:SetConVarR( convarR )
|
||||
color:SetConVarG( convarG )
|
||||
color:SetConVarB( convarB )
|
||||
|
||||
if ( convarA != nil ) then
|
||||
color:SetConVarA( convarA )
|
||||
end
|
||||
|
||||
self:AddPanel( color )
|
||||
|
||||
return color
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FillViaTable( Table )
|
||||
|
||||
self:SetInitialized( true )
|
||||
|
||||
self:SetName( Table.Text )
|
||||
|
||||
--
|
||||
-- If we have a function to create the control panel, use that
|
||||
--
|
||||
if ( Table.ControlPanelBuildFunction ) then
|
||||
|
||||
Table.ControlPanelBuildFunction( self )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:FillViaFunction( func )
|
||||
|
||||
func( self )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ControlValues( data )
|
||||
if ( data.label) then
|
||||
self:SetLabel( data.label )
|
||||
end
|
||||
if ( data.closed ) then
|
||||
self:SetExpanded( false )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function PANEL:AddControl( control, data )
|
||||
|
||||
local data = table.LowerKeyNames( data )
|
||||
local original = control
|
||||
control = string.lower( control )
|
||||
|
||||
-- Retired
|
||||
if ( control == "header" ) then
|
||||
|
||||
if ( data.description ) then
|
||||
local ctrl = self:Help( data.description )
|
||||
return ctrl
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if ( control == "textbox" ) then
|
||||
|
||||
local ctrl = self:TextEntry( data.label or "Untitled", data.command )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "label" ) then
|
||||
|
||||
local ctrl = self:Help( data.text )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "checkbox" or control == "toggle" ) then
|
||||
|
||||
local ctrl = self:CheckBox( data.label or "Untitled", data.command )
|
||||
|
||||
if ( data.help ) then
|
||||
self:ControlHelp( data.label .. ".help" )
|
||||
end
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "slider" ) then
|
||||
|
||||
local Decimals = 0
|
||||
if ( data.type && string.lower(data.type) == "float" ) then Decimals = 2 end
|
||||
|
||||
local ctrl = self:NumSlider( data.label or "Untitled", data.command, data.min or 0, data.max or 100, Decimals )
|
||||
|
||||
if ( data.help ) then
|
||||
self:ControlHelp( data.label .. ".help" )
|
||||
end
|
||||
|
||||
if ( data.default ) then
|
||||
ctrl:SetDefaultValue( data.default )
|
||||
elseif ( data.command ) then
|
||||
local cvar = GetConVar( data.command )
|
||||
if ( cvar ) then
|
||||
ctrl:SetDefaultValue( cvar:GetDefault() )
|
||||
end
|
||||
end
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "propselect" ) then
|
||||
|
||||
local ctrl = vgui.Create( "PropSelect", self )
|
||||
ctrl:ControlValues( data ) -- Yack.
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "matselect" ) then
|
||||
|
||||
local ctrl = vgui.Create( "MatSelect", self )
|
||||
ctrl:ControlValues( data ) -- Yack.
|
||||
self:AddPanel( ctrl )
|
||||
|
||||
Derma_Hook( ctrl.List, "Paint", "Paint", "Panel" )
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "ropematerial" ) then
|
||||
|
||||
local ctrl = vgui.Create( "RopeMaterial", self )
|
||||
ctrl:SetConVar( data.convar )
|
||||
self:AddPanel( ctrl )
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "button" ) then
|
||||
|
||||
local ctrl = vgui.Create( "DButton", self )
|
||||
|
||||
-- Note: Buttons created this way use the old method of calling commands,
|
||||
-- via LocalPlayer:ConCommand. This way is flawed. This way is legacy.
|
||||
-- The new way is to make buttons via controlpanel:Button( name, command, commandarg1, commandarg2 ) etc
|
||||
if ( data.command ) then
|
||||
function ctrl:DoClick() LocalPlayer():ConCommand( data.command ) end
|
||||
end
|
||||
|
||||
ctrl:SetText( data.label or data.text or "No Label" )
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "numpad" ) then
|
||||
|
||||
local ctrl = vgui.Create( "CtrlNumPad", self )
|
||||
ctrl:SetConVar1( data.command )
|
||||
ctrl:SetConVar2( data.command2 )
|
||||
ctrl:SetLabel1( data.label )
|
||||
ctrl:SetLabel2( data.label2 )
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
if ( control == "color" ) then
|
||||
|
||||
local ctrl = vgui.Create( "CtrlColor", self )
|
||||
ctrl:SetLabel( data.label )
|
||||
ctrl:SetConVarR( data.red )
|
||||
ctrl:SetConVarG( data.green )
|
||||
ctrl:SetConVarB( data.blue )
|
||||
ctrl:SetConVarA( data.alpha )
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
|
||||
if ( control == "combobox" ) then
|
||||
|
||||
if ( tostring( data.menubutton ) == "1" ) then
|
||||
|
||||
local ctrl = vgui.Create( "ControlPresets", self )
|
||||
ctrl:SetPreset( data.folder )
|
||||
if ( data.options ) then
|
||||
for k, v in pairs( data.options ) do
|
||||
ctrl:AddOption( k, v )
|
||||
end
|
||||
end
|
||||
|
||||
if ( data.cvars ) then
|
||||
for k, v in pairs( data.cvars ) do
|
||||
ctrl:AddConVar( v )
|
||||
end
|
||||
end
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
control = "listbox"
|
||||
|
||||
end
|
||||
|
||||
if ( control == "listbox" ) then
|
||||
|
||||
if ( data.height ) then
|
||||
|
||||
local ctrl = vgui.Create( "DListView" )
|
||||
ctrl:SetMultiSelect( false )
|
||||
ctrl:AddColumn( data.label or "unknown" )
|
||||
|
||||
if ( data.options ) then
|
||||
|
||||
for k, v in pairs( data.options ) do
|
||||
|
||||
local line = ctrl:AddLine( k )
|
||||
line.data = v
|
||||
|
||||
-- This is kind of broken because it only checks one convar
|
||||
-- instead of all of them. But this is legacy. It will do for now.
|
||||
for k, v in pairs( line.data ) do
|
||||
if ( GetConVarString( k ) == tostring( v ) ) then
|
||||
line:SetSelected( true )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
ctrl:SetTall( data.height )
|
||||
ctrl:SortByColumn( 1, false )
|
||||
|
||||
function ctrl:OnRowSelected( LineID, Line )
|
||||
for k, v in pairs( Line.data ) do
|
||||
RunConsoleCommand( k, v )
|
||||
end
|
||||
end
|
||||
|
||||
self:AddItem( ctrl )
|
||||
|
||||
return ctrl
|
||||
|
||||
else
|
||||
|
||||
local ctrl = vgui.Create( "CtrlListBox", self )
|
||||
|
||||
if ( data.options ) then
|
||||
for k, v in pairs( data.options ) do
|
||||
ctrl:AddOption( k, v )
|
||||
end
|
||||
end
|
||||
|
||||
local left = vgui.Create( "DLabel", self )
|
||||
left:SetText( data.label )
|
||||
left:SetDark( true )
|
||||
ctrl:SetHeight( 25 )
|
||||
ctrl:Dock( TOP )
|
||||
|
||||
self:AddItem( left, ctrl )
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( control == "materialgallery" ) then
|
||||
|
||||
local ctrl = vgui.Create( "MatSelect", self )
|
||||
--ctrl:ControlValues( data ) -- Yack.
|
||||
|
||||
ctrl:SetItemWidth( data.width or 32 )
|
||||
ctrl:SetItemHeight( data.height or 32 )
|
||||
ctrl:SetNumRows( data.rows or 4 )
|
||||
ctrl:SetConVar( data.convar or nil )
|
||||
|
||||
Derma_Hook( ctrl.List, "Paint", "Paint", "Panel" )
|
||||
|
||||
for name, tab in pairs( data.options ) do
|
||||
|
||||
local mat = tab.material
|
||||
local value = tab.value
|
||||
|
||||
tab.material = nil
|
||||
tab.value = nil
|
||||
|
||||
ctrl:AddMaterialEx( name, mat, value, tab )
|
||||
|
||||
end
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
local ctrl = vgui.Create( original, self )
|
||||
-- Fallback for scripts that relied on the old behaviour
|
||||
if ( !ctrl ) then
|
||||
ctrl = vgui.Create( control, self )
|
||||
end
|
||||
if ( ctrl ) then
|
||||
|
||||
if ( ctrl.ControlValues ) then
|
||||
ctrl:ControlValues( data )
|
||||
end
|
||||
|
||||
self:AddPanel( ctrl )
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
MsgN( "UNHANDLED CONTROL: ", control )
|
||||
PrintTable( data )
|
||||
MsgN( "\n\n" )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ControlPanel", PANEL, "DForm" )
|
||||
@@ -0,0 +1,173 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
include( "preset_editor.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.DropDown = vgui.Create( "DComboBox", self )
|
||||
self.DropDown.OnSelect = function( dropdown, index, value, data ) self:OnSelect( index, value, data ) end
|
||||
self.DropDown:SetText( "Presets" )
|
||||
self.DropDown:Dock( FILL )
|
||||
|
||||
self.Button = vgui.Create( "DImageButton", self )
|
||||
self.Button.DoClick = function() self:OpenPresetEditor() end
|
||||
self.Button:Dock( RIGHT )
|
||||
self.Button:SetToolTip( "#preset.edit" )
|
||||
self.Button:SetImage( "icon16/wrench.png" )
|
||||
self.Button:SetStretchToFit( false )
|
||||
self.Button:SetSize( 20, 20 )
|
||||
self.Button:DockMargin( 0, 0, 0, 0 )
|
||||
|
||||
self.AddButton = vgui.Create( "DImageButton", self )
|
||||
self.AddButton.DoClick = function()
|
||||
if ( !IsValid( self ) ) then return end
|
||||
|
||||
self:QuickSavePreset()
|
||||
end
|
||||
self.AddButton:Dock( RIGHT )
|
||||
self.AddButton:SetToolTip( "#preset.add" )
|
||||
self.AddButton:SetImage( "icon16/add.png" )
|
||||
self.AddButton:SetStretchToFit( false )
|
||||
self.AddButton:SetSize( 20, 20 )
|
||||
self.AddButton:DockMargin( 2, 0, 0, 0 )
|
||||
|
||||
self:SetTall( 20 )
|
||||
|
||||
self.Options = {}
|
||||
self.ConVars = {}
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetLabel( strName )
|
||||
|
||||
self.Label:SetText( strName )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddOption( strName, data )
|
||||
|
||||
self.DropDown:AddChoice( strName, data )
|
||||
|
||||
self.Options[ strName ] = data
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetOptions( Options )
|
||||
if ( Options ) then
|
||||
table.Merge( self.Options, Options )
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:OnSelect( index, value, data )
|
||||
|
||||
if ( !data ) then return end
|
||||
|
||||
for k, v in pairs( data ) do
|
||||
RunConsoleCommand( k, v )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:QuickSaveInternal( text )
|
||||
local tabValues = {}
|
||||
for k, v in pairs( self:GetConVars() ) do
|
||||
tabValues[ v ] = GetConVarString( v )
|
||||
end
|
||||
|
||||
presets.Add( self.m_strPreset, text, tabValues )
|
||||
self:Update()
|
||||
end
|
||||
|
||||
function PANEL:QuickSavePreset()
|
||||
Derma_StringRequest( "#preset.saveas_title", "#preset.saveas_desc", "", function( text )
|
||||
if ( !text || text:Trim() == "" ) then presets.BadNameAlert() return end
|
||||
|
||||
if ( presets.Exists( self.m_strPreset, text ) ) then
|
||||
presets.OverwritePresetPrompt( function()
|
||||
self:QuickSaveInternal( text )
|
||||
end )
|
||||
return
|
||||
end
|
||||
|
||||
self:QuickSaveInternal( text )
|
||||
end )
|
||||
end
|
||||
|
||||
function PANEL:OpenPresetEditor()
|
||||
|
||||
if ( !self.m_strPreset ) then return end
|
||||
|
||||
self.Window = vgui.Create( "PresetEditor" )
|
||||
self.Window:MakePopup()
|
||||
self.Window:Center()
|
||||
self.Window:SetType( self.m_strPreset )
|
||||
self.Window:SetConVars( self:GetConVars() )
|
||||
self.Window:SetPresetControl( self )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddConVar( convar )
|
||||
|
||||
table.insert( self.ConVars, convar )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetConVars()
|
||||
|
||||
return self.ConVars
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetPreset( strName )
|
||||
|
||||
self.m_strPreset = strName
|
||||
self:ReloadPresets()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ReloadPresets()
|
||||
|
||||
self:Clear()
|
||||
|
||||
for name, data in pairs( self.Options ) do
|
||||
self:AddOption( name, data )
|
||||
end
|
||||
|
||||
local Presets = presets.GetTable( self.m_strPreset )
|
||||
local sortedPresets, i = {}, 1
|
||||
for name in pairs( Presets ) do
|
||||
sortedPresets[ i ] = name
|
||||
i = i + 1
|
||||
end
|
||||
table.sort( sortedPresets )
|
||||
|
||||
for _, name in ipairs( sortedPresets ) do
|
||||
self.DropDown:AddChoice( name, Presets[ name ] )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Update()
|
||||
|
||||
self:ReloadPresets()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Clear()
|
||||
|
||||
self.DropDown:Clear()
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ControlPresets", PANEL, "Panel" )
|
||||
59
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrlcolor.lua
Normal file
59
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrlcolor.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.Mixer = vgui.Create( "DColorMixer", self )
|
||||
self.Mixer:Dock( FILL )
|
||||
|
||||
self:SetTall( 245 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout( x, y )
|
||||
|
||||
-- Magic number, the target width for self.Mixer
|
||||
-- Number picked to that Palette would not have a gap, at button size 17
|
||||
local targetWidth = 272
|
||||
|
||||
-- Don't scale the Mixer in width, keep it to the target width
|
||||
local s = math.max( ( self:GetWide() - targetWidth ) / 2, 0 )
|
||||
self.Mixer:DockMargin( s, 8, s, 0 )
|
||||
|
||||
-- Ugly hack, because of the docking system
|
||||
self.OldMixerW = self.OldMixerW or self.Mixer:GetWide()
|
||||
|
||||
-- Number of panels in one row
|
||||
local ColorRows = math.ceil( #self.Mixer.Palette:GetChildren() / 3 )
|
||||
|
||||
-- Set the button size closest to fill the Mixer width
|
||||
local bSize = math.floor( self:GetWide() / ColorRows )
|
||||
self.Mixer.Palette:SetButtonSize( math.min( bSize, 17 ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint()
|
||||
-- Invisible background!
|
||||
end
|
||||
|
||||
function PANEL:SetLabel( text ) self.Mixer:SetLabel( text ) end
|
||||
function PANEL:SetConVarR( cvar ) self.Mixer:SetConVarR( cvar ) end
|
||||
function PANEL:SetConVarG( cvar ) self.Mixer:SetConVarG( cvar ) end
|
||||
function PANEL:SetConVarB( cvar ) self.Mixer:SetConVarB( cvar ) end
|
||||
function PANEL:SetConVarA( cvar ) self.Mixer:SetConVarA( cvar ) end
|
||||
function PANEL:GetConVarR() return self.Mixer:GetConVarR() end
|
||||
function PANEL:GetConVarG() return self.Mixer:GetConVarG() end
|
||||
function PANEL:GetConVarB() return self.Mixer:GetConVarB() end
|
||||
function PANEL:GetConVarA() return self.Mixer:GetConVarA() end
|
||||
|
||||
vgui.Register( "CtrlColor", PANEL, "DPanel" )
|
||||
118
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrllistbox.lua
Normal file
118
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrllistbox.lua
Normal file
@@ -0,0 +1,118 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
--AccessorFunc( PANEL, "m_ConVarR", "ConVarR" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Init
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self.ConVars = {}
|
||||
self.Options = {}
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: AddOption
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:AddOption( strName, tabConVars )
|
||||
|
||||
self:AddChoice( strName, tabConVars )
|
||||
|
||||
for k, v in pairs( tabConVars ) do
|
||||
self.ConVars[ k ] = 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: OnSelect
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:OnSelect( index, value, data )
|
||||
|
||||
for k, v in pairs( data ) do
|
||||
|
||||
RunConsoleCommand( k, tostring( v ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Think
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Think( CheckConvarChanges )
|
||||
|
||||
self:CheckConVarChanges()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ConVarsChanged
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:ConVarsChanged()
|
||||
|
||||
for k, v in pairs( self.ConVars ) do
|
||||
|
||||
if ( self[ k ] == nil ) then return true end
|
||||
if ( self[ k ] != GetConVarString( k ) ) then return true end
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CheckForMatch
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:CheckForMatch( cvars )
|
||||
|
||||
if ( table.IsEmpty( cvars ) ) then return false end
|
||||
|
||||
for k, v in pairs( cvars ) do
|
||||
|
||||
if ( tostring(v) != GetConVarString( k ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CheckConVarChanges
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:CheckConVarChanges()
|
||||
|
||||
if (!self:ConVarsChanged()) then return end
|
||||
|
||||
for k, v in pairs( self.ConVars ) do
|
||||
self[ k ] = GetConVarString( k )
|
||||
end
|
||||
|
||||
for k, v in pairs( self.Data ) do
|
||||
|
||||
if ( self:CheckForMatch( v ) ) then
|
||||
self:SetText( self:GetOptionText(k) )
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "CtrlListBox", PANEL, "DComboBox" )
|
||||
117
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrlnumpad.lua
Normal file
117
gamemodes/sandbox/gamemode/spawnmenu/controls/ctrlnumpad.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_ConVar1", "ConVar1" )
|
||||
AccessorFunc( PANEL, "m_ConVar2", "ConVar2" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Init
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self.NumPad1 = vgui.Create( "DBinder", self )
|
||||
self.Label1 = vgui.Create( "DLabel", self )
|
||||
self.Label1:SetDark( true )
|
||||
|
||||
self.NumPad2 = vgui.Create( "DBinder", self )
|
||||
self.Label2 = vgui.Create( "DLabel", self )
|
||||
self.Label2:SetDark( true )
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
|
||||
self:SetHeight( 200 )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetLabel1
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:SetLabel1( txt )
|
||||
if ( !txt ) then return end
|
||||
self.Label1:SetText( txt )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetLabel2
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:SetLabel2( txt )
|
||||
if ( !txt ) then return end
|
||||
self.Label2:SetText( txt )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetConVar1
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:SetConVar1( cvar )
|
||||
self.NumPad1:SetConVar( cvar )
|
||||
self.m_ConVar1 = cvar
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetConVar2
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:SetConVar2( cvar )
|
||||
self.NumPad2:SetConVar( cvar )
|
||||
self.m_ConVar2 = cvar
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Init
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
self:SetTall( 70 )
|
||||
|
||||
self.NumPad1:InvalidateLayout( true )
|
||||
self.NumPad1:SetSize( 100, 50 )
|
||||
|
||||
if ( self.m_ConVar2 ) then
|
||||
self.NumPad2:InvalidateLayout( true )
|
||||
self.NumPad2:SetSize( 100, 50 )
|
||||
end
|
||||
|
||||
if ( !self.m_ConVar2 ) then
|
||||
|
||||
self.Label1:SizeToContents()
|
||||
|
||||
self.NumPad2:SetVisible( false )
|
||||
self.Label2:SetVisible( false )
|
||||
|
||||
self.NumPad1:CenterHorizontal( 0.5 )
|
||||
self.NumPad1:AlignTop( 20 )
|
||||
|
||||
self.Label1:CenterHorizontal()
|
||||
self.Label1:AlignTop( 0 )
|
||||
|
||||
else
|
||||
|
||||
self.Label1:SizeToContents()
|
||||
self.Label2:SizeToContents()
|
||||
|
||||
self.NumPad2:SetVisible( true )
|
||||
self.Label2:SetVisible( true )
|
||||
|
||||
self.NumPad1:CenterHorizontal( 0.25 )
|
||||
self.Label1:CenterHorizontal( 0.25 )
|
||||
self.NumPad1:AlignTop( 20 )
|
||||
|
||||
self.NumPad2:CenterHorizontal( 0.75 )
|
||||
self.Label2:CenterHorizontal( 0.75 )
|
||||
self.NumPad2:AlignTop( 20 )
|
||||
self.Label2:AlignTop( 0 )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "CtrlNumPad", PANEL, "DPanel" )
|
||||
17
gamemodes/sandbox/gamemode/spawnmenu/controls/manifest.lua
Normal file
17
gamemodes/sandbox/gamemode/spawnmenu/controls/manifest.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
include( "control_presets.lua" )
|
||||
include( "ropematerial.lua" )
|
||||
|
||||
include( "ctrlnumpad.lua" )
|
||||
include( "ctrlcolor.lua" )
|
||||
include( "ctrllistbox.lua" )
|
||||
272
gamemodes/sandbox/gamemode/spawnmenu/controls/preset_editor.lua
Normal file
272
gamemodes/sandbox/gamemode/spawnmenu/controls/preset_editor.lua
Normal file
@@ -0,0 +1,272 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_strType", "Type" )
|
||||
AccessorFunc( PANEL, "m_ConVars", "ConVars" )
|
||||
AccessorFunc( PANEL, "m_PresetControl", "PresetControl" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetSize( 450, 350 )
|
||||
self:SetMinWidth( 450 )
|
||||
self:SetMinHeight( 350 )
|
||||
self:SetSizable( true )
|
||||
self:SetTitle( "#preset.editor" )
|
||||
self:DockPadding( 6, 29, 6, 6 )
|
||||
|
||||
local pnlTop = vgui.Create( "Panel", self )
|
||||
pnlTop:Dock( FILL )
|
||||
pnlTop:DockMargin( 0, 0, 0, 5 )
|
||||
|
||||
self.PresetList = vgui.Create( "DListView", pnlTop )
|
||||
self.PresetList:Dock( LEFT )
|
||||
self.PresetList:DockMargin( 0, 0, 5, 0 )
|
||||
self.PresetList:SetWide( 150 )
|
||||
self.PresetList:SetMultiSelect( false )
|
||||
self.PresetList:SetSortable( false )
|
||||
self.PresetList.OnRowSelected = function( s, idx, pnl ) self:OnPresetSelected( pnl ) end
|
||||
|
||||
local pnlEditor = vgui.Create( "DPanel", pnlTop )
|
||||
pnlEditor:Dock( FILL )
|
||||
|
||||
self.pnlDetails = vgui.Create( "DProperties", pnlEditor )
|
||||
self.pnlDetails:Dock( FILL )
|
||||
self.pnlDetails:DockMargin( 5, 5, 5, 5 )
|
||||
|
||||
----------
|
||||
|
||||
local pnlModify = vgui.Create( "Panel", pnlEditor )
|
||||
pnlModify:Dock( BOTTOM )
|
||||
pnlModify:SetTall( 20 )
|
||||
pnlModify:DockMargin( 5, 0, 5, 5 )
|
||||
|
||||
local btnDelete = vgui.Create( "DButton", pnlModify )
|
||||
btnDelete.DoClick = function() self:Delete() end
|
||||
btnDelete:SetTooltip( "#preset.delete" )
|
||||
btnDelete:SetImage( "icon16/bin.png" )
|
||||
btnDelete:SetText( "" )
|
||||
btnDelete:Dock( RIGHT )
|
||||
btnDelete:SetWide( 25 )
|
||||
btnDelete:SetEnabled( false )
|
||||
|
||||
self.txtRename = vgui.Create( "DTextEntry", pnlModify )
|
||||
self.txtRename:Dock( FILL )
|
||||
self.txtRename:SetEnabled( false )
|
||||
self.txtRename:SetTooltip( "#preset.rename" )
|
||||
|
||||
local btnRename = vgui.Create( "DButton", pnlModify )
|
||||
btnRename:SetTooltip( "#preset.save" )
|
||||
btnRename:SetImage( "icon16/disk.png" )
|
||||
btnRename:SetText( "" )
|
||||
btnRename:Dock( RIGHT )
|
||||
btnRename:DockMargin( 5, 0, 5, 0 )
|
||||
btnRename:SetWide( 24 )
|
||||
btnRename.DoClick = function() self:SaveChanges() end
|
||||
btnRename:SetEnabled( false )
|
||||
|
||||
----------
|
||||
|
||||
local bottom = vgui.Create( "Panel", self )
|
||||
bottom:Dock( BOTTOM )
|
||||
bottom:SetTall( 30 )
|
||||
|
||||
self.pnlAdd = vgui.Create( "DPanel", bottom )
|
||||
self.pnlAdd:Dock( FILL )
|
||||
self.pnlAdd:DockPadding( 5, 5, 5, 5 )
|
||||
self.pnlAdd:DockMargin( 0, 0, 5, 0 )
|
||||
|
||||
self.txtName = vgui.Create( "DTextEntry", self.pnlAdd )
|
||||
self.txtName:SetTooltip( "#preset.addnew_field" )
|
||||
self.txtName:Dock( FILL )
|
||||
self.txtName:DockMargin( 0, 0, 5, 0 )
|
||||
self.txtName.OnChange = function( s ) self.btnAdd:SetEnabled( s:GetText():Trim() != "" ) end
|
||||
|
||||
self.btnAdd = vgui.Create( "DButton", self.pnlAdd )
|
||||
self.btnAdd:SetText( "#preset.addnew" )
|
||||
self.btnAdd:Dock( RIGHT )
|
||||
self.btnAdd:SetEnabled( false )
|
||||
self.btnAdd.DoClick = function() self:Add() end
|
||||
|
||||
----------
|
||||
|
||||
local pnlClose = vgui.Create( "DPanel", bottom )
|
||||
pnlClose:Dock( RIGHT )
|
||||
pnlClose:SetWide( 100 )
|
||||
pnlClose:DockPadding( 5, 5, 5, 5 )
|
||||
|
||||
local btnCloseIt = vgui.Create( "DButton", pnlClose )
|
||||
btnCloseIt:SetText( "#preset.close" )
|
||||
btnCloseIt:Dock( FILL )
|
||||
btnCloseIt.DoClick = function() self:Remove() end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetType( strType )
|
||||
|
||||
self.m_strType = strType
|
||||
|
||||
self.PresetList:AddColumn( self:GetType() )
|
||||
self:Update()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnPresetSelected( item )
|
||||
|
||||
local name = item:GetValue( 1 )
|
||||
|
||||
self.txtRename:SetText( name )
|
||||
for id, pnl in ipairs( self.txtRename:GetParent():GetChildren() ) do pnl:SetEnabled( true ) end
|
||||
|
||||
self.pnlDetails:Clear()
|
||||
for cvar, val in SortedPairs( item:GetTable().Data ) do
|
||||
local Row = self.pnlDetails:CreateRow( name, cvar:lower() )
|
||||
|
||||
if ( tonumber( val ) != nil && false ) then
|
||||
Row:Setup( "Float", { min = 0, max = 1000 } )
|
||||
Row:SetValue( val )
|
||||
else
|
||||
Row:Setup( "Generic" )
|
||||
end
|
||||
|
||||
Row:SetValue( val )
|
||||
Row.__Value = val
|
||||
Row.DataChanged = function( s, value ) Row.__Value = value end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Update()
|
||||
|
||||
self.PresetList:Clear()
|
||||
self.pnlDetails:Clear()
|
||||
self.txtRename:SetText( "" )
|
||||
|
||||
local Presets = presets.GetTable( self:GetType() )
|
||||
local sortedPresets, i = {}, 1
|
||||
for name in pairs( Presets ) do
|
||||
sortedPresets[i] = name
|
||||
i = i + 1
|
||||
end
|
||||
table.sort( sortedPresets )
|
||||
|
||||
for _, name in ipairs( sortedPresets ) do
|
||||
local item = self.PresetList:AddLine( name )
|
||||
item.Data = Presets[ name ]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SelectPresetByName( name )
|
||||
|
||||
for id, line in pairs( self.PresetList:GetLines() ) do
|
||||
if ( line:GetValue( 1 ) != name ) then continue end
|
||||
self.PresetList:SelectItem( line )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Delete()
|
||||
|
||||
if ( !self.PresetList:GetSelectedLine() || !IsValid( self.PresetList:GetLine( self.PresetList:GetSelectedLine() ) ) ) then return end
|
||||
|
||||
local Selected = self.PresetList:GetLine( self.PresetList:GetSelectedLine() ):GetValue( 1 ):Trim()
|
||||
if ( Selected == "" ) then return end
|
||||
|
||||
presets.Remove( self:GetType(), Selected )
|
||||
self:Update()
|
||||
|
||||
if ( self:GetPresetControl() ) then self:GetPresetControl():Update() end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SaveChangesInternal( Selected, ToName )
|
||||
|
||||
local tabValues = {}
|
||||
local cat = self.pnlDetails:GetCategory( Selected )
|
||||
|
||||
-- WARNING: This will discard ConVars in the preset that no longer exist on the tool/whatever this preset is for
|
||||
for k, v in pairs( self:GetConVars() ) do
|
||||
if ( cat:GetRow( v:lower() ) ) then
|
||||
tabValues[ v:lower() ] = cat:GetRow( v:lower() ).__Value
|
||||
end
|
||||
end
|
||||
|
||||
presets.Rename( self:GetType(), Selected, ToName ) -- Raname the preset if necessary
|
||||
presets.Add( self:GetType(), ToName, tabValues ) -- Update the values
|
||||
|
||||
self:Update()
|
||||
|
||||
self.txtRename:SetText( "" )
|
||||
self:SelectPresetByName( ToName )
|
||||
|
||||
if ( self:GetPresetControl() ) then self:GetPresetControl():Update() end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SaveChanges()
|
||||
|
||||
if ( !self.PresetList:GetSelectedLine() || !IsValid( self.PresetList:GetLine( self.PresetList:GetSelectedLine() ) ) ) then return end
|
||||
|
||||
local Selected = self.PresetList:GetLine( self.PresetList:GetSelectedLine() ):GetValue( 1 ):Trim()
|
||||
if ( Selected == "" ) then return end
|
||||
|
||||
local ToName = self.txtRename:GetValue():Trim()
|
||||
if ( !ToName || ToName == "" ) then presets.BadNameAlert() return end
|
||||
|
||||
if ( presets.Exists( self:GetType(), ToName ) && Selected != ToName ) then
|
||||
presets.OverwritePresetPrompt( function()
|
||||
self:SaveChangesInternal( Selected, ToName )
|
||||
end )
|
||||
return
|
||||
end
|
||||
|
||||
self:SaveChangesInternal( Selected, ToName )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:InternalAdd( ToName )
|
||||
|
||||
local tabValues = {}
|
||||
for k, v in pairs( self:GetConVars() ) do
|
||||
tabValues[ v ] = GetConVarString( v:lower() )
|
||||
end
|
||||
|
||||
presets.Add( self:GetType(), ToName, tabValues )
|
||||
self:Update()
|
||||
|
||||
self.txtName:SetText( "" )
|
||||
self:SelectPresetByName( ToName )
|
||||
|
||||
if ( self:GetPresetControl() ) then self:GetPresetControl():Update() end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Add()
|
||||
|
||||
if ( !self:GetConVars() ) then return end
|
||||
|
||||
local ToName = self.txtName:GetValue():Trim()
|
||||
if ( !ToName || ToName == "" ) then presets.BadNameAlert() return end
|
||||
|
||||
if ( presets.Exists( self:GetType(), ToName ) ) then
|
||||
presets.OverwritePresetPrompt( function()
|
||||
self:InternalAdd( ToName )
|
||||
end )
|
||||
return
|
||||
end
|
||||
|
||||
self:InternalAdd( ToName )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "PresetEditor", PANEL, "DFrame" )
|
||||
@@ -0,0 +1,46 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
list.Set( "RopeMaterials", "#ropematerial.rope", "cable/rope" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.cable", "cable/cable2" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.xbeam", "cable/xbeam" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.laser", "cable/redlaser" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.electric", "cable/blue_elec" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.physbeam", "cable/physbeam" )
|
||||
list.Set( "RopeMaterials", "#ropematerial.hydra", "cable/hydra" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetItemWidth( 0.14 )
|
||||
self:SetItemHeight( 0.3 )
|
||||
self:SetAutoHeight( true )
|
||||
|
||||
local mats = list.Get( "RopeMaterials" )
|
||||
for k, v in pairs( mats ) do
|
||||
|
||||
self:AddMaterial( k, v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
draw.RoundedBox( 4, 0, 0, w, h, Color( 128, 128, 128, 255 ) )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "RopeMaterial", PANEL, "MatSelect" )
|
||||
67
gamemodes/sandbox/gamemode/spawnmenu/creationmenu.lua
Normal file
67
gamemodes/sandbox/gamemode/spawnmenu/creationmenu.lua
Normal file
@@ -0,0 +1,67 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
include( "creationmenu/manifest.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.CreationTabs = {}
|
||||
|
||||
self:SetFadeTime( 0 )
|
||||
self:Populate()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetCreationTab( id )
|
||||
|
||||
return self.CreationTabs[ id ]
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetCreationTabs()
|
||||
|
||||
return self.CreationTabs
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Populate()
|
||||
|
||||
local tabs = spawnmenu.GetCreationTabs()
|
||||
|
||||
for k, v in SortedPairsByMemberValue( tabs, "Order" ) do
|
||||
|
||||
--
|
||||
-- Here we create a panel and populate it on the first paint
|
||||
-- that way everything is created on the first view instead of
|
||||
-- being created on load.
|
||||
--
|
||||
local pnl = vgui.Create( "Panel" )
|
||||
|
||||
local tab = self:AddSheet( k, pnl, v.Icon, nil, nil, v.Tooltip )
|
||||
self.CreationTabs[ k ] = tab
|
||||
|
||||
-- Populate the panel
|
||||
-- We have to add the timer to make sure g_Spawnmenu is available
|
||||
-- in case some addon needs it ready when populating the creation tab.
|
||||
timer.Simple( 0, function()
|
||||
if ( !IsValid( pnl ) ) then return end
|
||||
local childpnl = v.Function()
|
||||
childpnl:SetParent( pnl )
|
||||
childpnl:Dock( FILL )
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "CreationMenu", PANEL, "DPropertySheet" )
|
||||
@@ -0,0 +1,110 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
include( "contenticon.lua" )
|
||||
include( "postprocessicon.lua" )
|
||||
|
||||
include( "contentcontainer.lua" )
|
||||
include( "contentsidebar.lua" )
|
||||
|
||||
include( "contenttypes/custom.lua" )
|
||||
include( "contenttypes/npcs.lua" )
|
||||
include( "contenttypes/weapons.lua" )
|
||||
include( "contenttypes/entities.lua" )
|
||||
include( "contenttypes/postprocess.lua" )
|
||||
include( "contenttypes/vehicles.lua" )
|
||||
include( "contenttypes/saves.lua" )
|
||||
include( "contenttypes/dupes.lua" )
|
||||
|
||||
include( "contenttypes/gameprops.lua" )
|
||||
include( "contenttypes/addonprops.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_pSelectedPanel", "SelectedPanel" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
|
||||
self.CategoryTable = {}
|
||||
|
||||
self.HorizontalDivider = vgui.Create( "DHorizontalDivider", self )
|
||||
self.HorizontalDivider:Dock( FILL )
|
||||
self.HorizontalDivider:SetLeftWidth( 192 )
|
||||
self.HorizontalDivider:SetLeftMin( 100 )
|
||||
self.HorizontalDivider:SetRightMin( 100 )
|
||||
if ( ScrW() >= 1024 ) then self.HorizontalDivider:SetLeftMin( 192 ) self.HorizontalDivider:SetRightMin( 400 ) end
|
||||
self.HorizontalDivider:SetDividerWidth( 6 )
|
||||
self.HorizontalDivider:SetCookieName( "SpawnMenuCreationMenuDiv" )
|
||||
|
||||
self.ContentNavBar = vgui.Create( "ContentSidebar", self.HorizontalDivider )
|
||||
self.HorizontalDivider:SetLeft( self.ContentNavBar )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:EnableModify()
|
||||
self.ContentNavBar:EnableModify()
|
||||
end
|
||||
|
||||
function PANEL:EnableSearch( ... )
|
||||
self.ContentNavBar:EnableSearch( ... )
|
||||
end
|
||||
|
||||
function PANEL:CallPopulateHook( HookName )
|
||||
|
||||
hook.Call( HookName, GAMEMODE, self, self.ContentNavBar.Tree, self.OldSpawnlists )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SwitchPanel( panel )
|
||||
|
||||
if ( IsValid( self.SelectedPanel ) ) then
|
||||
self.SelectedPanel:SetVisible( false )
|
||||
self.SelectedPanel = nil
|
||||
end
|
||||
|
||||
self.SelectedPanel = panel
|
||||
|
||||
if ( !IsValid( panel ) ) then return end
|
||||
|
||||
self.HorizontalDivider:SetRight( self.SelectedPanel )
|
||||
self.HorizontalDivider:InvalidateLayout( true )
|
||||
|
||||
self.SelectedPanel:SetVisible( true )
|
||||
self:InvalidateParent()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnSizeChanged()
|
||||
self.HorizontalDivider:LoadCookies()
|
||||
end
|
||||
|
||||
vgui.Register( "SpawnmenuContentPanel", PANEL, "DPanel" )
|
||||
|
||||
local function CreateContentPanel()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
|
||||
ctrl.OldSpawnlists = ctrl.ContentNavBar.Tree:AddNode( "#spawnmenu.category.browse", "icon16/cog.png" )
|
||||
|
||||
ctrl:EnableModify()
|
||||
hook.Call( "PopulatePropMenu", GAMEMODE )
|
||||
ctrl:CallPopulateHook( "PopulateContent" )
|
||||
|
||||
ctrl.OldSpawnlists:MoveToFront()
|
||||
ctrl.OldSpawnlists:SetExpanded( true )
|
||||
|
||||
return ctrl
|
||||
|
||||
end
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.content_tab", CreateContentPanel, "icon16/application_view_tile.png", -10 )
|
||||
@@ -0,0 +1,224 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
DEFINE_BASECLASS( "DScrollPanel" )
|
||||
|
||||
AccessorFunc( PANEL, "m_pControllerPanel", "ControllerPanel" )
|
||||
AccessorFunc( PANEL, "m_strCategoryName", "CategoryName" )
|
||||
AccessorFunc( PANEL, "m_bTriggerSpawnlistChange", "TriggerSpawnlistChange" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Init
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
|
||||
self.IconList = vgui.Create( "DTileLayout", self:GetCanvas() )
|
||||
self.IconList:SetBaseSize( 64 )
|
||||
self.IconList:MakeDroppable( "SandboxContentPanel", true )
|
||||
self.IconList:SetSelectionCanvas( true )
|
||||
--self.IconList:SetUseLiveDrag( true )
|
||||
self.IconList:Dock( TOP )
|
||||
self.IconList.OnModified = function() self:OnModified() end
|
||||
self.IconList.OnMousePressed = function( s, btn )
|
||||
|
||||
-- A bit of a hack
|
||||
s:EndBoxSelection()
|
||||
if ( btn != MOUSE_RIGHT ) then DPanel.OnMousePressed( s, btn ) end
|
||||
|
||||
end
|
||||
self.IconList.OnMouseReleased = function( s, btn )
|
||||
|
||||
DPanel.OnMouseReleased( s, btn )
|
||||
|
||||
if ( btn != MOUSE_RIGHT || s:GetReadOnly() ) then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.newlabel", function()
|
||||
|
||||
local label = vgui.Create( "ContentHeader" )
|
||||
self:Add( label )
|
||||
|
||||
-- Move the label to player's cursor, but make sure it's per line, not per icon
|
||||
local x, y = self.IconList:ScreenToLocal( input.GetCursorPos() )
|
||||
label:MoveToAfter( self.IconList:GetClosestChild( self:GetCanvas():GetWide(), y ) )
|
||||
|
||||
self:OnModified()
|
||||
|
||||
-- Scroll to the newly added item
|
||||
--[[timer.Simple( 0, function()
|
||||
local x, y = label:GetPos()
|
||||
self.VBar:AnimateTo( y - self:GetTall() / 2 + label:GetTall() / 2, 0.5, 0, 0.5 )
|
||||
end )]]
|
||||
|
||||
end ):SetIcon( "icon16/text_heading_1.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
self.IconList.ContentContainer = self
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Add( pnl )
|
||||
|
||||
self.IconList:Add( pnl )
|
||||
|
||||
if ( pnl.InstallMenu ) then
|
||||
pnl:InstallMenu( self )
|
||||
end
|
||||
|
||||
self:Layout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Layout()
|
||||
|
||||
self.IconList:Layout()
|
||||
self:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout( w, h )
|
||||
|
||||
BaseClass.PerformLayout( self, w, h )
|
||||
self.IconList:SetMinHeight( self:GetTall() - 16 )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RebuildAll
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:RebuildAll( proppanel )
|
||||
|
||||
for k, v in ipairs( self.IconList:GetChildren() ) do
|
||||
|
||||
v:RebuildSpawnIcon()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetCount
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:GetCount()
|
||||
|
||||
return #self.IconList:GetChildren()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Clear()
|
||||
|
||||
self.IconList:Clear()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetTriggerSpawnlistChange( bTrigger )
|
||||
|
||||
self.m_bTriggerSpawnlistChange = bTrigger
|
||||
self.IconList:SetReadOnly( !bTrigger )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnModified()
|
||||
|
||||
if ( !self:GetTriggerSpawnlistChange() ) then return end
|
||||
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ContentsToTable( contentpanel )
|
||||
|
||||
local tab = {}
|
||||
|
||||
for k, v in ipairs( self.IconList:GetChildren() ) do
|
||||
|
||||
v:ToTable( tab )
|
||||
|
||||
end
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Copy()
|
||||
|
||||
local copy = vgui.Create( "ContentContainer", self:GetParent() )
|
||||
copy:CopyBase( self )
|
||||
|
||||
copy.IconList:CopyContents( self.IconList )
|
||||
|
||||
return copy
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ContentContainer", PANEL, "DScrollPanel" )
|
||||
|
||||
hook.Add( "SpawnlistOpenGenericMenu", "DragAndDropSelectionMenu", function( canvas )
|
||||
|
||||
if ( canvas:GetReadOnly() ) then return end
|
||||
|
||||
local selected = canvas:GetSelectedChildren()
|
||||
|
||||
local menu = DermaMenu()
|
||||
|
||||
-- This is less than ideal
|
||||
local spawnicons = 0
|
||||
local icon = nil
|
||||
for id, pnl in pairs( selected ) do
|
||||
if ( pnl.InternalAddResizeMenu ) then
|
||||
spawnicons = spawnicons + 1
|
||||
icon = pnl
|
||||
end
|
||||
end
|
||||
|
||||
if ( spawnicons > 0 ) then
|
||||
icon:InternalAddResizeMenu( menu, function( w, h )
|
||||
|
||||
for id, pnl in pairs( selected ) do
|
||||
if ( !pnl.InternalAddResizeMenu ) then continue end
|
||||
pnl:SetSize( w, h )
|
||||
pnl:InvalidateLayout( true )
|
||||
pnl:GetParent():OnModified()
|
||||
pnl:GetParent():Layout()
|
||||
pnl:SetModel( pnl:GetModelName(), pnl:GetSkinID(), pnl:GetBodyGroup() )
|
||||
end
|
||||
|
||||
end, language.GetPhrase( "spawnmenu.menu.resizex" ):format( spawnicons ) )
|
||||
|
||||
menu:AddOption( language.GetPhrase( "spawnmenu.menu.rerenderx" ):format( spawnicons ), function()
|
||||
for id, pnl in pairs( selected ) do
|
||||
if ( !pnl.RebuildSpawnIcon ) then continue end
|
||||
pnl:RebuildSpawnIcon()
|
||||
end
|
||||
end ):SetIcon( "icon16/picture.png" )
|
||||
end
|
||||
|
||||
menu:AddSpacer()
|
||||
|
||||
menu:AddOption( language.GetPhrase( "spawnmenu.menu.deletex" ):format( #selected ), function()
|
||||
|
||||
for k, v in pairs( selected ) do
|
||||
v:Remove()
|
||||
end
|
||||
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
|
||||
end ):SetIcon( "icon16/bin_closed.png" )
|
||||
|
||||
menu:Open()
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,140 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
surface.CreateFont( "ContentHeader", {
|
||||
font = "Helvetica",
|
||||
size = 50,
|
||||
weight = 1000
|
||||
} )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetFont( "ContentHeader" )
|
||||
self:SetBright( true )
|
||||
self:SetExpensiveShadow( 2, Color( 0, 0, 0, 130 ) )
|
||||
|
||||
self:SetSize( 64, 64 )
|
||||
|
||||
self.OwnLine = true
|
||||
self:SetAutoStretch( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
self:SizeToContents()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
|
||||
local w = self:GetContentSize()
|
||||
|
||||
-- Don't let the text overflow the parent's width
|
||||
if ( IsValid( self:GetParent() ) ) then
|
||||
w = math.min( w, self:GetParent():GetWide() - 32 )
|
||||
end
|
||||
|
||||
-- Add a bit more room so it looks nice as a textbox :)
|
||||
-- And make sure it has at least some width
|
||||
self:SetSize( math.max( w, 64 ) + 16, 64 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ToTable( bigtable )
|
||||
|
||||
local tab = {}
|
||||
|
||||
tab.type = "header"
|
||||
tab.text = self:GetText()
|
||||
|
||||
table.insert( bigtable, tab )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Copy()
|
||||
|
||||
local copy = vgui.Create( "ContentHeader", self:GetParent() )
|
||||
copy:SetText( self:GetText() )
|
||||
copy:CopyBounds( self )
|
||||
|
||||
return copy
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PaintOver( w, h )
|
||||
|
||||
self:DrawSelections()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnLabelTextChanged( txt )
|
||||
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
return txt
|
||||
|
||||
end
|
||||
|
||||
function PANEL:IsEnabled()
|
||||
|
||||
-- This is a hack!
|
||||
return !IsValid( self:GetParent() ) || !self:GetParent().GetReadOnly || !self:GetParent():GetReadOnly()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoRightClick()
|
||||
|
||||
local pCanvas = self:GetSelectionCanvas()
|
||||
if ( IsValid( pCanvas ) && pCanvas:NumSelectedChildren() > 0 && self:IsSelected() ) then
|
||||
return hook.Run( "SpawnlistOpenGenericMenu", pCanvas )
|
||||
end
|
||||
|
||||
self:OpenMenu()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:UpdateColours( skin )
|
||||
|
||||
if ( self:GetHighlight() ) then return self:SetTextStyleColor( skin.Colours.Label.Highlight ) end
|
||||
if ( self:GetBright() ) then return self:SetTextStyleColor( skin.Colours.Label.Bright ) end
|
||||
if ( self:GetDark() ) then return self:SetTextStyleColor( skin.Colours.Label.Dark ) end
|
||||
|
||||
return self:SetTextStyleColor( skin.Colours.Label.Default )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OpenMenu()
|
||||
|
||||
-- Do not allow removal from read only panels
|
||||
if ( IsValid( self:GetParent() ) && self:GetParent().GetReadOnly && self:GetParent():GetReadOnly() ) then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function() self:Remove() hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/bin_closed.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ContentHeader", PANEL, "DLabelEditable" )
|
||||
|
||||
spawnmenu.AddContentType( "header", function( container, obj )
|
||||
|
||||
if ( !obj.text || !isstring( obj.text ) ) then return end
|
||||
|
||||
local label = vgui.Create( "ContentHeader", container )
|
||||
label:SetText( obj.text )
|
||||
|
||||
container:Add( label )
|
||||
|
||||
return label
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,449 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
local matOverlay_Normal = Material( "gui/ContentIcon-normal.png" )
|
||||
local matOverlay_Hovered = Material( "gui/ContentIcon-hovered.png" )
|
||||
|
||||
local matOverlay_AdminOnly = Material( "icon16/shield.png" )
|
||||
local matOverlay_NPCWeapon = Material( "icon16/monkey.png" )
|
||||
local matOverlay_NPCWeaponSelected = Material( "icon16/monkey_tick.png" )
|
||||
|
||||
AccessorFunc( PANEL, "m_Color", "Color" )
|
||||
AccessorFunc( PANEL, "m_Type", "ContentType" )
|
||||
AccessorFunc( PANEL, "m_SpawnName", "SpawnName" )
|
||||
AccessorFunc( PANEL, "m_NPCWeapon", "NPCWeapon" )
|
||||
AccessorFunc( PANEL, "m_bAdminOnly", "AdminOnly" )
|
||||
AccessorFunc( PANEL, "m_bIsNPCWeapon", "IsNPCWeapon" )
|
||||
|
||||
local function DoGenericSpawnmenuRightclickMenu( self )
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.copy", function() SetClipboardText( self:GetSpawnName() ) end ):SetIcon( "icon16/page_copy.png" )
|
||||
if ( isfunction( self.OpenMenuExtra ) ) then
|
||||
self:OpenMenuExtra( menu )
|
||||
end
|
||||
|
||||
if ( !IsValid( self:GetParent() ) || !self:GetParent().GetReadOnly || !self:GetParent():GetReadOnly() ) then
|
||||
menu:AddSpacer()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function() self:Remove() hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/bin_closed.png" )
|
||||
end
|
||||
menu:Open()
|
||||
end
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
self:SetSize( 128, 128 )
|
||||
self:SetText( "" )
|
||||
self:SetDoubleClickingEnabled( false )
|
||||
|
||||
self.Image = self:Add( "DImage" )
|
||||
self.Image:SetPos( 3, 3 )
|
||||
self.Image:SetSize( 128 - 6, 128 - 6 )
|
||||
self.Image:SetVisible( false )
|
||||
|
||||
self.Label = self:Add( "DLabel" )
|
||||
self.Label:Dock( BOTTOM )
|
||||
self.Label:SetTall( 18 )
|
||||
self.Label:SetContentAlignment( 5 )
|
||||
self.Label:DockMargin( 4, 0, 4, 6 )
|
||||
self.Label:SetTextColor( color_white )
|
||||
self.Label:SetExpensiveShadow( 1, Color( 0, 0, 0, 200 ) )
|
||||
|
||||
self.Border = 0
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetName( name )
|
||||
|
||||
self:SetTooltip( name )
|
||||
self.Label:SetText( name )
|
||||
self.m_NiceName = name
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetMaterial( name )
|
||||
|
||||
self.m_MaterialName = name
|
||||
|
||||
local mat = Material( name )
|
||||
|
||||
-- Look for the old style material
|
||||
if ( !mat || mat:IsError() ) then
|
||||
|
||||
name = name:Replace( "entities/", "VGUI/entities/" )
|
||||
name = name:Replace( ".png", "" )
|
||||
mat = Material( name )
|
||||
|
||||
end
|
||||
|
||||
-- Couldn't find any material.. just return
|
||||
if ( !mat || mat:IsError() ) then
|
||||
return
|
||||
end
|
||||
|
||||
self.Image:SetMaterial( mat )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoRightClick()
|
||||
|
||||
local pCanvas = self:GetSelectionCanvas()
|
||||
if ( IsValid( pCanvas ) && pCanvas:NumSelectedChildren() > 0 && self:IsSelected() ) then
|
||||
return hook.Run( "SpawnlistOpenGenericMenu", pCanvas )
|
||||
end
|
||||
|
||||
self:OpenMenu()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoClick()
|
||||
end
|
||||
|
||||
function PANEL:OpenMenu()
|
||||
end
|
||||
|
||||
function PANEL:OnDepressionChanged( b )
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
if ( self.Depressed && !self.Dragging ) then
|
||||
if ( self.Border != 8 ) then
|
||||
self.Border = 8
|
||||
self:OnDepressionChanged( true )
|
||||
end
|
||||
else
|
||||
if ( self.Border != 0 ) then
|
||||
self.Border = 0
|
||||
self:OnDepressionChanged( false )
|
||||
end
|
||||
end
|
||||
|
||||
render.PushFilterMag( TEXFILTER.ANISOTROPIC )
|
||||
render.PushFilterMin( TEXFILTER.ANISOTROPIC )
|
||||
|
||||
self.Image:PaintAt( 3 + self.Border, 3 + self.Border, 128 - 8 - self.Border * 2, 128 - 8 - self.Border * 2 )
|
||||
|
||||
render.PopFilterMin()
|
||||
render.PopFilterMag()
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
|
||||
if ( !dragndrop.IsDragging() && ( self:IsHovered() || self.Depressed || self:IsChildHovered() ) ) then
|
||||
|
||||
surface.SetMaterial( matOverlay_Hovered )
|
||||
self.Label:Hide()
|
||||
|
||||
else
|
||||
|
||||
surface.SetMaterial( matOverlay_Normal )
|
||||
self.Label:Show()
|
||||
|
||||
end
|
||||
|
||||
surface.DrawTexturedRect( self.Border, self.Border, w-self.Border*2, h-self.Border*2 )
|
||||
|
||||
if ( self:GetAdminOnly() ) then
|
||||
surface.SetMaterial( matOverlay_AdminOnly )
|
||||
surface.DrawTexturedRect( self.Border + 8, self.Border + 8, 16, 16 )
|
||||
end
|
||||
|
||||
-- This whole thing could be more dynamic
|
||||
if ( self:GetIsNPCWeapon() ) then
|
||||
surface.SetMaterial( matOverlay_NPCWeapon )
|
||||
|
||||
if ( self:GetSpawnName() == GetConVarString( "gmod_npcweapon" ) ) then
|
||||
surface.SetMaterial( matOverlay_NPCWeaponSelected )
|
||||
end
|
||||
|
||||
surface.DrawTexturedRect( w - self.Border - 24, self.Border + 8, 16, 16 )
|
||||
end
|
||||
self:ScanForNPCWeapons()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ScanForNPCWeapons()
|
||||
if ( self.HasScanned ) then return end
|
||||
self.HasScanned = true
|
||||
|
||||
for _, v in pairs( list.Get( "NPCUsableWeapons" ) ) do
|
||||
if ( v.class == self:GetSpawnName() ) then
|
||||
self:SetIsNPCWeapon( true )
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:PaintOver( w, h )
|
||||
|
||||
self:DrawSelections()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:ToTable( bigtable )
|
||||
|
||||
local tab = {}
|
||||
|
||||
tab.type = self:GetContentType()
|
||||
tab.nicename = self.m_NiceName
|
||||
tab.material = self.m_MaterialName
|
||||
tab.admin = self:GetAdminOnly()
|
||||
tab.spawnname = self:GetSpawnName()
|
||||
tab.weapon = self:GetNPCWeapon()
|
||||
|
||||
table.insert( bigtable, tab )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Copy()
|
||||
|
||||
local copy = vgui.Create( "ContentIcon", self:GetParent() )
|
||||
|
||||
copy:SetContentType( self:GetContentType() )
|
||||
copy:SetSpawnName( self:GetSpawnName() )
|
||||
copy:SetName( self.m_NiceName )
|
||||
copy:SetMaterial( self.m_MaterialName )
|
||||
copy:SetNPCWeapon( self:GetNPCWeapon() )
|
||||
copy:SetAdminOnly( self:GetAdminOnly() )
|
||||
copy:CopyBase( self )
|
||||
copy.DoClick = self.DoClick
|
||||
copy.OpenMenu = self.OpenMenu
|
||||
copy.OpenMenuExtra = self.OpenMenuExtra
|
||||
|
||||
return copy
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ContentIcon", PANEL, "DButton" )
|
||||
|
||||
spawnmenu.AddContentType( "entity", function( container, obj )
|
||||
|
||||
if ( !obj.material ) then return end
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "entity" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
icon:SetMaterial( obj.material )
|
||||
icon:SetAdminOnly( obj.admin )
|
||||
icon:SetColor( Color( 205, 92, 92, 255 ) )
|
||||
|
||||
-- Generate a nice tooltip with extra info.
|
||||
local ENTinfo = scripted_ents.Get( obj.spawnname )
|
||||
local toolTip = language.GetPhrase( obj.nicename )
|
||||
if ( !ENTinfo ) then ENTinfo = list.Get( "SpawnableEntities" )[ obj.spawnname ] end
|
||||
if ( ENTinfo ) then
|
||||
local extraInfo = ""
|
||||
if ( ENTinfo.Information and ENTinfo.Information != "" ) then extraInfo = extraInfo .. "\n" .. ENTinfo.Information end
|
||||
if ( ENTinfo.Author and ENTinfo.Author != "" ) then extraInfo = extraInfo .. "\nAuthor: " .. ENTinfo.Author end
|
||||
if ( #extraInfo > 0 ) then toolTip = toolTip .. "\n" .. extraInfo end
|
||||
end
|
||||
|
||||
icon:SetTooltip( toolTip )
|
||||
|
||||
icon.DoClick = function()
|
||||
RunConsoleCommand( "gm_spawnsent", obj.spawnname )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
end
|
||||
icon.OpenMenuExtra = function( self, menu )
|
||||
menu:AddOption( "#spawnmenu.menu.spawn_with_toolgun", function() RunConsoleCommand( "gmod_tool", "creator" ) RunConsoleCommand( "creator_type", "0" ) RunConsoleCommand( "creator_name", obj.spawnname ) end ):SetIcon( "icon16/brick_add.png" )
|
||||
end
|
||||
icon.OpenMenu = DoGenericSpawnmenuRightclickMenu
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddContentType( "vehicle", function( container, obj )
|
||||
|
||||
if ( !obj.material ) then return end
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "vehicle" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
icon:SetMaterial( obj.material )
|
||||
icon:SetAdminOnly( obj.admin )
|
||||
icon:SetColor( Color( 0, 0, 0, 255 ) )
|
||||
icon.DoClick = function()
|
||||
RunConsoleCommand( "gm_spawnvehicle", obj.spawnname )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
end
|
||||
icon.OpenMenuExtra = function( self, menu )
|
||||
menu:AddOption( "#spawnmenu.menu.spawn_with_toolgun", function() RunConsoleCommand( "gmod_tool", "creator" ) RunConsoleCommand( "creator_type", "1" ) RunConsoleCommand( "creator_name", obj.spawnname ) end ):SetIcon( "icon16/brick_add.png" )
|
||||
end
|
||||
icon.OpenMenu = DoGenericSpawnmenuRightclickMenu
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
|
||||
local gmod_npcweapon = CreateConVar( "gmod_npcweapon", "", { FCVAR_ARCHIVE }, "Overrides the weapon all spawnmenu NPCs will spawn with. Set to \"\" to not override." )
|
||||
|
||||
spawnmenu.AddContentType( "npc", function( container, obj )
|
||||
|
||||
if ( !obj.material ) then return end
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
if ( !obj.weapon ) then obj.weapon = {} end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "npc" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
icon:SetMaterial( obj.material )
|
||||
icon:SetAdminOnly( obj.admin )
|
||||
icon:SetNPCWeapon( obj.weapon )
|
||||
icon:SetColor( Color( 244, 164, 96, 255 ) )
|
||||
|
||||
icon.DoClick = function()
|
||||
local weapon = table.Random( obj.weapon ) or ""
|
||||
if ( gmod_npcweapon:GetString() != "" ) then weapon = gmod_npcweapon:GetString() end
|
||||
|
||||
RunConsoleCommand( "gmod_spawnnpc", obj.spawnname, weapon )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
end
|
||||
|
||||
icon.OpenMenuExtra = function( self, menu )
|
||||
local weapon = table.Random( obj.weapon ) or ""
|
||||
if ( gmod_npcweapon:GetString() != "" ) then weapon = gmod_npcweapon:GetString() end
|
||||
|
||||
menu:AddOption( "#spawnmenu.menu.spawn_with_toolgun", function()
|
||||
RunConsoleCommand( "gmod_tool", "creator" ) RunConsoleCommand( "creator_type", "2" )
|
||||
RunConsoleCommand( "creator_name", obj.spawnname ) RunConsoleCommand( "creator_arg", weapon )
|
||||
end ):SetIcon( "icon16/brick_add.png" )
|
||||
|
||||
-- Quick access to spawning NPCs with a spcific weapon without the need to change gmod_npcweapon
|
||||
if ( table.IsEmpty( obj.weapon ) ) then return end
|
||||
|
||||
local subMenu, swg = menu:AddSubMenu( "#spawnmenu.menu.spawn_with_weapon" )
|
||||
swg:SetIcon( "icon16/gun.png" )
|
||||
|
||||
subMenu:AddOption( "#menubar.npcs.noweapon", function() RunConsoleCommand( "gmod_spawnnpc", obj.spawnname, "" ) end ):SetIcon( "icon16/cross.png" )
|
||||
|
||||
-- Kind of a hack!
|
||||
local function addWeps( subm, weps )
|
||||
if ( table.Count( weps ) < 1 ) then return end
|
||||
|
||||
subMenu:AddSpacer()
|
||||
for title, class in SortedPairs( weps ) do
|
||||
subMenu:AddOption( title, function() RunConsoleCommand( "gmod_spawnnpc", obj.spawnname, class ) end ):SetIcon( "icon16/gun.png" )
|
||||
end
|
||||
end
|
||||
|
||||
local weaps = {}
|
||||
for _, class in pairs( obj.weapon ) do
|
||||
if ( class == "" ) then continue end
|
||||
weaps[ language.GetPhrase( class ) ] = class
|
||||
end
|
||||
addWeps( subMenu, weaps )
|
||||
|
||||
local weaps = {}
|
||||
for _, t in pairs( list.Get( "NPCUsableWeapons" ) ) do
|
||||
if ( table.HasValue( obj.weapon, t.class ) ) then continue end
|
||||
weaps[ language.GetPhrase( t.title ) ] = t.class
|
||||
end
|
||||
addWeps( subMenu, weaps )
|
||||
|
||||
end
|
||||
icon.OpenMenu = DoGenericSpawnmenuRightclickMenu
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddContentType( "weapon", function( container, obj )
|
||||
|
||||
if ( !obj.material ) then return end
|
||||
if ( !obj.nicename ) then return end
|
||||
if ( !obj.spawnname ) then return end
|
||||
|
||||
local icon = vgui.Create( "ContentIcon", container )
|
||||
icon:SetContentType( "weapon" )
|
||||
icon:SetSpawnName( obj.spawnname )
|
||||
icon:SetName( obj.nicename )
|
||||
icon:SetMaterial( obj.material )
|
||||
icon:SetAdminOnly( obj.admin )
|
||||
icon:SetColor( Color( 135, 206, 250, 255 ) )
|
||||
|
||||
-- Generate a nice tooltip with extra info.
|
||||
local SWEPinfo = weapons.Get( obj.spawnname )
|
||||
local toolTip = language.GetPhrase( obj.nicename )
|
||||
if ( !SWEPinfo ) then SWEPinfo = list.Get( "Weapon" )[ obj.spawnname ] end
|
||||
if ( SWEPinfo ) then
|
||||
toolTip = toolTip .. "\n"
|
||||
-- These 2 really should be one
|
||||
if ( SWEPinfo.Purpose and SWEPinfo.Purpose != "" ) then toolTip = toolTip .. "\n" .. SWEPinfo.Purpose end
|
||||
if ( SWEPinfo.Instructions and SWEPinfo.Instructions != "" ) then toolTip = toolTip .. "\n" .. SWEPinfo.Instructions end
|
||||
|
||||
if ( SWEPinfo.Author and SWEPinfo.Author != "" ) then toolTip = toolTip .. "\nAuthor: " .. SWEPinfo.Author end
|
||||
end
|
||||
|
||||
toolTip = toolTip .. "\n\n" .. language.GetPhrase( "spawnmenu.mmb_weapons" )
|
||||
|
||||
icon:SetTooltip( toolTip )
|
||||
|
||||
icon.DoClick = function()
|
||||
|
||||
RunConsoleCommand( "gm_giveswep", obj.spawnname )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
|
||||
end
|
||||
|
||||
icon.DoMiddleClick = function()
|
||||
|
||||
RunConsoleCommand( "gm_spawnswep", obj.spawnname )
|
||||
surface.PlaySound( "ui/buttonclickrelease.wav" )
|
||||
|
||||
end
|
||||
|
||||
icon.OpenMenuExtra = function( self, menu )
|
||||
menu:AddOption( "#spawnmenu.menu.spawn_with_toolgun", function() RunConsoleCommand( "gmod_tool", "creator" ) RunConsoleCommand( "creator_type", "3" ) RunConsoleCommand( "creator_name", obj.spawnname ) end ):SetIcon( "icon16/brick_add.png" )
|
||||
|
||||
if ( self:GetIsNPCWeapon() ) then
|
||||
local opt = menu:AddOption( "#spawnmenu.menu.use_as_npc_gun", function() RunConsoleCommand( "gmod_npcweapon", self:GetSpawnName() ) end )
|
||||
if ( self:GetSpawnName() == GetConVarString( "gmod_npcweapon" ) ) then
|
||||
opt:SetIcon( "icon16/monkey_tick.png" )
|
||||
else
|
||||
opt:SetIcon( "icon16/monkey.png" )
|
||||
end
|
||||
end
|
||||
end
|
||||
icon.OpenMenu = DoGenericSpawnmenuRightclickMenu
|
||||
|
||||
if ( IsValid( container ) ) then
|
||||
container:Add( icon )
|
||||
end
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,161 @@
|
||||
--[[
|
||||
| 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()
|
||||
|
||||
PANEL.Base = "Panel"
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.CurrentSearch = ""
|
||||
self.OldResults = -1
|
||||
self.RebuildResults = false
|
||||
|
||||
self:Dock( TOP )
|
||||
self:SetHeight( 20 )
|
||||
self:DockMargin( 0, 0, 0, 3 )
|
||||
|
||||
self.Search = self:Add( "DTextEntry" )
|
||||
self.Search:Dock( FILL )
|
||||
self.Search:SetPlaceholderText( "#spawnmenu.search" )
|
||||
|
||||
self.Search.OnEnter = function() self:RefreshResults() end
|
||||
self.Search.OnFocusChanged = function( _, b ) if ( b ) then self.ContentPanel:SwitchPanel( self.PropPanel ) end end
|
||||
self.Search:SetTooltip( "#spawnmenu.enter_search" )
|
||||
|
||||
local btn = self.Search:Add( "DImageButton" )
|
||||
|
||||
btn:SetImage( "icon16/magnifier.png" )
|
||||
btn:SetText( "" )
|
||||
btn:Dock( RIGHT )
|
||||
btn:DockMargin( 4, 2, 4, 2 )
|
||||
btn:SetSize( 16, 16 )
|
||||
btn:SetTooltip( "#spawnmenu.press_search" )
|
||||
btn.DoClick = function()
|
||||
self:RefreshResults()
|
||||
end
|
||||
|
||||
self.Search.OnKeyCode = function( p, code )
|
||||
|
||||
if ( code == KEY_F1 ) then hook.Run( "OnSpawnMenuClose" ) end
|
||||
if ( code == KEY_ESCAPE ) then hook.Run( "OnSpawnMenuClose" ) end
|
||||
|
||||
end
|
||||
|
||||
self.PropPanel = vgui.Create( "ContentContainer", self )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
-- Some sort of placeholder
|
||||
local Header = self:Add( "ContentHeader" )
|
||||
Header:SetText( "#spawnmenu.enter_search" )
|
||||
self.PropPanel:Add( Header )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint()
|
||||
-- This is a bit of a hack, if there was a request to rebuild the results from the search indexer
|
||||
-- Do it when the player next sees the search panel, in case they got the spawnmenu closed
|
||||
-- Think hook causes unexpected 1 frame duplication of all the elements
|
||||
if ( self.RebuildResults ) then
|
||||
self.RebuildResults = false
|
||||
self:RefreshResults( self.CurrentSearch )
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:SetSearchType( stype, hookname )
|
||||
self.m_strSearchType = stype
|
||||
hook.Add( hookname, "AddSearchContent_" .. hookname, function( pnlContent, tree, node )
|
||||
self.ContentPanel = pnlContent
|
||||
end )
|
||||
hook.Add( "SearchUpdate", "SearchUpdate_" .. hookname, function()
|
||||
if ( !g_SpawnMenu:IsVisible() ) then self.RebuildResults = true return end
|
||||
self:RefreshResults( self.CurrentSearch )
|
||||
end )
|
||||
|
||||
-- This stuff is only for the primary search
|
||||
if ( hookname != "PopulateContent" ) then return end
|
||||
|
||||
g_SpawnMenu.SearchPropPanel = self.PropPanel
|
||||
hook.Add( "StartSearch", "StartSearch", function()
|
||||
|
||||
if ( g_SpawnMenu:IsVisible() ) then return hook.Run( "OnSpawnMenuClose" ) end
|
||||
|
||||
hook.Run( "OnSpawnMenuOpen" )
|
||||
hook.Run( "OnTextEntryGetFocus", self.Search )
|
||||
|
||||
self.Search:RequestFocus()
|
||||
self.Search:SetText( "" )
|
||||
|
||||
--
|
||||
-- If we don't call this we'd have to press F1 twice to close it!
|
||||
-- It's in a timer because of some good reason that!
|
||||
--
|
||||
timer.Simple( 0.1, function() g_SpawnMenu:HangOpen( false ) end )
|
||||
|
||||
self.ContentPanel:SwitchPanel( self.PropPanel )
|
||||
|
||||
end )
|
||||
end
|
||||
|
||||
function PANEL:RefreshResults( str )
|
||||
|
||||
if ( !str ) then -- User tried to search for something
|
||||
self.CurrentSearch = self.Search:GetText()
|
||||
str = self.CurrentSearch
|
||||
self.OldResults = -1
|
||||
else
|
||||
-- Don't force open the search when you click away from search while this function is called from cl_search_models.lua
|
||||
if ( self.ContentPanel.SelectedPanel != self.PropPanel ) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if ( !str or str == "" ) then return end
|
||||
|
||||
local results = search.GetResults( str, self.m_strSearchType, GetConVarNumber( "sbox_search_maxresults" ) )
|
||||
for id, result in ipairs( results ) do
|
||||
if ( !IsValid( result.icon ) ) then ErrorNoHalt( "Failed to create icon for " .. ( result.words && isstring( result.words[ 1 ] ) && result.words[ 1 ] || result.text ).. "\n" ) continue end
|
||||
result.icon:SetParent( vgui.GetWorldPanel() ) -- Don't parent the icons to search panel prematurely
|
||||
end
|
||||
|
||||
-- I know this is not perfect, but this is the best I am willing to do with how the search library was set up
|
||||
if ( self.OldResults == #results ) then -- No updates, don't rebuild
|
||||
for id, result in ipairs( results ) do
|
||||
if ( IsValid( result.icon ) ) then result.icon:Remove() end -- Kill all icons
|
||||
end
|
||||
return
|
||||
end
|
||||
self.OldResults = #results
|
||||
|
||||
self.PropPanel:Clear()
|
||||
|
||||
local Header = self:Add( "ContentHeader" )
|
||||
Header:SetText( #results .. " Results for \"" .. str .. "\"" )
|
||||
self.PropPanel:Add( Header )
|
||||
|
||||
for k, v in ipairs( results ) do
|
||||
self:AddSearchResult( v.text, v.func, v.icon )
|
||||
end
|
||||
|
||||
self.PropPanel:SetParent( self.ContentPanel )
|
||||
self.ContentPanel:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddSearchResult( text, func, icon )
|
||||
|
||||
if ( !IsValid( icon ) ) then return end
|
||||
|
||||
icon:SetParent( self.PropPanel )
|
||||
self.PropPanel:Add( icon )
|
||||
|
||||
end
|
||||
@@ -0,0 +1,96 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
include( "contentsidebartoolbox.lua" )
|
||||
|
||||
local pnlSearch = vgui.RegisterFile( "contentsearch.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.Tree = vgui.Create( "DTree", self )
|
||||
self.Tree:SetClickOnDragHover( true )
|
||||
self.Tree.OnNodeSelected = function( Tree, Node ) hook.Call( "ContentSidebarSelection", GAMEMODE, self:GetParent(), Node ) end
|
||||
self.Tree:Dock( FILL )
|
||||
self.Tree:SetBackgroundColor( Color( 240, 240, 240, 255 ) )
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:EnableSearch( stype, hookname )
|
||||
self.Search = vgui.CreateFromTable( pnlSearch, self )
|
||||
self.Search:SetSearchType( stype, hookname or "PopulateContent" )
|
||||
end
|
||||
|
||||
function PANEL:EnableModify()
|
||||
|
||||
self:EnableSearch()
|
||||
self:CreateSaveNotification()
|
||||
|
||||
self.Toolbox = vgui.Create( "ContentSidebarToolbox", self )
|
||||
|
||||
hook.Add( "OpenToolbox", "OpenToolbox", function()
|
||||
|
||||
if ( !IsValid( self.Toolbox ) ) then return end
|
||||
|
||||
self.Toolbox:Open()
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:CreateSaveNotification()
|
||||
|
||||
local SavePanel = vgui.Create( "Panel", self )
|
||||
SavePanel:Dock( TOP )
|
||||
SavePanel:SetVisible( false )
|
||||
SavePanel:DockMargin( 8, 1, 8, 4 )
|
||||
|
||||
local SaveButton = vgui.Create( "DButton", SavePanel )
|
||||
SaveButton:Dock( FILL )
|
||||
SaveButton:SetIcon( "icon16/disk.png" )
|
||||
SaveButton:SetText( "#spawnmenu.savechanges" )
|
||||
SaveButton.DoClick = function()
|
||||
|
||||
SavePanel:SlideUp( 0.2 )
|
||||
hook.Run( "OnSaveSpawnlist" )
|
||||
|
||||
end
|
||||
|
||||
local RevertButton = vgui.Create( "DButton", SavePanel )
|
||||
RevertButton:Dock( RIGHT )
|
||||
RevertButton:SetIcon( "icon16/arrow_rotate_clockwise.png" )
|
||||
RevertButton:SetText( "" )
|
||||
RevertButton:SetTooltip( "#spawnmenu.revert_tooptip" )
|
||||
RevertButton:SetWide( 26 )
|
||||
RevertButton:DockMargin( 4, 0, 0, 0 )
|
||||
RevertButton.DoClick = function()
|
||||
|
||||
SavePanel:SlideUp( 0.2 )
|
||||
hook.Run( "OnRevertSpawnlist" )
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "SpawnlistContentChanged", "ShowSaveButton", function()
|
||||
|
||||
if ( SavePanel:IsVisible() ) then return end
|
||||
|
||||
SavePanel:SlideDown( 0.2 )
|
||||
|
||||
GAMEMODE:AddHint( "EditingSpawnlistsSave", 5 )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ContentSidebar", PANEL, "DPanel" )
|
||||
@@ -0,0 +1,115 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
include( "contentheader.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
Derma_Hook( PANEL, "Paint", "Paint", "Tree" )
|
||||
PANEL.m_bBackground = true -- Hack for above
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetOpenSize( 200 )
|
||||
self:DockPadding( 5, 5, 5, 5 )
|
||||
|
||||
local label = vgui.Create( "DTextEntry", self )
|
||||
label:Dock( TOP )
|
||||
label:SetZPos( 1 )
|
||||
label:DockMargin( 0, 0, 0, 2 )
|
||||
label:SetTooltip( "#spawnmenu.listname_tooltip" )
|
||||
|
||||
local panel = vgui.Create( "DPanel", self )
|
||||
panel:Dock( TOP )
|
||||
panel:SetZPos( 2 )
|
||||
panel:SetSize( 24, 24 )
|
||||
panel:DockPadding( 2, 2, 2, 2 )
|
||||
|
||||
local Button = vgui.Create( "DImageButton", panel )
|
||||
Button:SetImage( "icon16/text_heading_1.png" )
|
||||
Button:Dock( LEFT )
|
||||
Button:SetStretchToFit( false )
|
||||
Button:SetSize( 20, 20 )
|
||||
Button:SetCursor( "sizeall" )
|
||||
Button:SetTooltip( "#spawnmenu.header_tooltip" )
|
||||
Button:Droppable( "SandboxContentPanel" )
|
||||
|
||||
Button.OnDrop = function( s, target )
|
||||
|
||||
local label = vgui.Create( "ContentHeader", target )
|
||||
return label
|
||||
|
||||
end
|
||||
|
||||
local panel = vgui.Create( "Panel", self )
|
||||
panel:Dock( FILL )
|
||||
panel:SetZPos( 3 )
|
||||
|
||||
local icon_filter = vgui.Create( "DTextEntry", panel )
|
||||
icon_filter:Dock( TOP )
|
||||
icon_filter:SetUpdateOnType( true )
|
||||
icon_filter:SetPlaceholderText( "#spawnmenu.quick_filter" )
|
||||
icon_filter:DockMargin( 0, 2, 0, 1 )
|
||||
|
||||
local icons = vgui.Create( "DIconBrowser", panel )
|
||||
icons:Dock( FILL )
|
||||
|
||||
icon_filter.OnValueChange = function( s, str )
|
||||
icons:FilterByText( str )
|
||||
end
|
||||
|
||||
local overlay = vgui.Create( "DPanel", self )
|
||||
overlay:SetZPos( 9999 )
|
||||
overlay.Paint = function( s, w, h )
|
||||
surface.SetDrawColor( 0, 0, 0, 200 )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
end
|
||||
self.Overlay = overlay
|
||||
|
||||
--
|
||||
-- If we select a node from the sidebar, update the text/icon/actions in the toolbox (at the bottom)
|
||||
--
|
||||
hook.Add( "ContentSidebarSelection", "SidebarToolboxSelection", function( pnlContent, node )
|
||||
|
||||
if ( !IsValid( node ) || !IsValid( label ) || !IsValid( icons ) ) then return end
|
||||
|
||||
if ( node.CustomSpawnlist ) then
|
||||
label:SetText( node:GetText() )
|
||||
icons:SelectIcon( node:GetIcon() )
|
||||
icons:ScrollToSelected()
|
||||
overlay:SetVisible( false )
|
||||
else
|
||||
label:SetText( "" )
|
||||
overlay:SetVisible( true )
|
||||
end
|
||||
|
||||
label.OnChange = function()
|
||||
if ( !node.CustomSpawnlist ) then return end
|
||||
node:SetText( label:GetText() )
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end
|
||||
|
||||
icons.OnChange = function()
|
||||
if ( !node.CustomSpawnlist ) then return end
|
||||
node:SetIcon( icons:GetSelectedIcon() )
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
-- Not using docking because it will mess up other elements using docking!
|
||||
self.Overlay:SetSize( self:GetSize() )
|
||||
end
|
||||
|
||||
vgui.Register( "ContentSidebarToolbox", PANEL, "DDrawer" )
|
||||
@@ -0,0 +1,172 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local function AddRecursive( pnl, folder, path, wildcard )
|
||||
|
||||
local files, folders = file.Find( folder .. "*", path )
|
||||
if ( !files ) then MsgN( "Warning! Not opening '" .. folder .. "' because we cannot search in it!" ) return false end
|
||||
|
||||
local added = false
|
||||
|
||||
for k, v in ipairs( files ) do
|
||||
|
||||
if ( !string.EndsWith( v, ".mdl" ) ) then continue end
|
||||
|
||||
local cp = spawnmenu.GetContentType( "model" )
|
||||
if ( cp ) then
|
||||
cp( pnl, { model = folder .. v } )
|
||||
added = true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
for k, v in ipairs( folders ) do
|
||||
|
||||
local added_rec = AddRecursive( pnl, folder .. v .. "/", path, wildcard )
|
||||
added = added || added_rec
|
||||
|
||||
end
|
||||
|
||||
return added
|
||||
|
||||
end
|
||||
|
||||
local function recurseAddFilesSpawnlist( folder, pathid, list )
|
||||
|
||||
local addedLabel = false
|
||||
|
||||
local files, folders = file.Find( folder .. "/*", pathid )
|
||||
for id, file in pairs( files or {} ) do
|
||||
if ( file:EndsWith( ".mdl" ) ) then
|
||||
if ( !addedLabel ) then
|
||||
table.insert( list, { type = "header", text = folder } )
|
||||
addedLabel = true
|
||||
end
|
||||
|
||||
table.insert( list, { type = "model", model = folder .. "/" .. file } )
|
||||
end
|
||||
end
|
||||
|
||||
for id, fold in pairs( folders or {} ) do
|
||||
recurseAddFilesSpawnlist( folder .. "/" .. fold, pathid, list )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function GenerateSpawnlistFromAddon( folder, path, name )
|
||||
|
||||
local contents = {}
|
||||
recurseAddFilesSpawnlist( folder, path, contents )
|
||||
|
||||
AddPropsOfParent( g_SpawnMenu.CustomizableSpawnlistNode.SMContentPanel, g_SpawnMenu.CustomizableSpawnlistNode, 0, { [ folder ] = {
|
||||
icon = "icon16/page.png",
|
||||
id = math.random( 0, 999999 ), -- Eeehhhh
|
||||
name = name or folder,
|
||||
parentid = 0,
|
||||
contents = contents
|
||||
} } )
|
||||
|
||||
-- We added a new spawnlist, show the save changes button
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
|
||||
end
|
||||
|
||||
local function AddonsRightClick( self )
|
||||
|
||||
if ( !IsValid( self ) || !self.wsid || self.wsid == "0" ) then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.openaddononworkshop", function()
|
||||
steamworks.ViewFile( self.wsid )
|
||||
end ):SetIcon( "icon16/link_go.png" )
|
||||
|
||||
menu:AddOption( "#spawnmenu.createautospawnlist", function()
|
||||
|
||||
GenerateSpawnlistFromAddon( "models", self.searchPath, self.searchPath )
|
||||
|
||||
end ):SetIcon( "icon16/page_add.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function RefreshAddons( MyNode )
|
||||
|
||||
local ViewPanel = MyNode.ViewPanel
|
||||
|
||||
for _, addon in SortedPairsByMemberValue( engine.GetAddons(), "title" ) do
|
||||
|
||||
if ( !addon.downloaded || !addon.mounted ) then continue end
|
||||
if ( addon.models <= 0 ) then continue end
|
||||
|
||||
local models = MyNode:AddNode( addon.title .. " (" .. addon.models .. ")", "icon16/bricks.png" )
|
||||
models.DoClick = function()
|
||||
|
||||
ViewPanel:Clear()
|
||||
|
||||
local anyAdded = AddRecursive( ViewPanel, "models/", addon.title, "*.mdl" )
|
||||
if ( !anyAdded ) then
|
||||
local text = "<font=ContentHeader>" .. language.GetPhrase( "spawnmenu.failedtofindmodels" ) .. "\n\n" .. tostring( addon.title ) .. " (ID: " .. tostring( addon.wsid ) .. ")" .. "</font>"
|
||||
|
||||
local msg = vgui.Create( "Panel", ViewPanel )
|
||||
msg.Paint = function( s, w, h )
|
||||
-- Shadow. Ew.
|
||||
local parsedShadow = markup.Parse( "<colour=0,0,0,130>" .. text .. "</colour>", s:GetParent():GetWide() )
|
||||
parsedShadow:Draw( 2, 2 )
|
||||
|
||||
-- The actual text
|
||||
local parsed = markup.Parse( text, s:GetParent():GetWide() )
|
||||
parsed:Draw( 0, 0 )
|
||||
|
||||
-- Size to contents. Ew.
|
||||
s:SetSize( parsed:GetWidth(), parsed:GetHeight() )
|
||||
end
|
||||
ViewPanel:Add( msg )
|
||||
end
|
||||
|
||||
MyNode.pnlContent:SwitchPanel( ViewPanel )
|
||||
|
||||
end
|
||||
models.DoRightClick = AddonsRightClick
|
||||
models.wsid = addon.wsid
|
||||
models.searchPath = addon.title
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local myAddonsNode
|
||||
hook.Add( "PopulateContent", "AddonProps", function( pnlContent, tree, node )
|
||||
|
||||
local myViewPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
myViewPanel:SetVisible( false )
|
||||
myViewPanel.IconList:SetReadOnly( true )
|
||||
|
||||
myAddonsNode = node:AddNode( "#spawnmenu.category.addons", "icon16/folder_database.png" )
|
||||
myAddonsNode.ViewPanel = myViewPanel
|
||||
myAddonsNode.pnlContent = pnlContent
|
||||
|
||||
RefreshAddons( myAddonsNode )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "GameContentChanged", "RefreshSpawnmenuAddons", function()
|
||||
|
||||
if ( !IsValid( myAddonsNode ) ) then return end
|
||||
|
||||
-- TODO: Maybe be more advaced and do not delete => recreate all the nodes, only delete nodes for addons that were removed, add only the new ones?
|
||||
myAddonsNode:Clear()
|
||||
myAddonsNode.ViewPanel:Clear()
|
||||
|
||||
RefreshAddons( myAddonsNode )
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,296 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local AddCustomizableNode = nil
|
||||
|
||||
local function SetupCustomNode( node, pnlContent, needsapp )
|
||||
|
||||
node.CustomSpawnlist = !node.AddonSpawnlist -- Used to determine which nodes ContentSidebarToolBox can edit
|
||||
|
||||
-- This spawnlist needs a certain app mounted before it will show up.
|
||||
if ( needsapp && needsapp != "" ) then
|
||||
node:SetVisible( IsMounted( needsapp ) )
|
||||
node.NeedsApp = needsapp
|
||||
|
||||
if ( !IsMounted( needsapp ) ) then
|
||||
-- Make it look different
|
||||
node:SetAlpha( 200 )
|
||||
|
||||
-- Give a detailed tooltip explaining why it looks different
|
||||
local name = language.GetPhrase( "spawnmenu.mountablegame" )
|
||||
for id, t in pairs( engine.GetGames() ) do
|
||||
if ( needsapp == t.folder ) then name = t.title break end
|
||||
end
|
||||
node:SetTooltip( string.format( language.GetPhrase( "spawnmenu.spawnlistnocontent" ), name ) )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
node.SetupCopy = function( self, copy )
|
||||
|
||||
SetupCustomNode( copy, pnlContent, needsapp )
|
||||
|
||||
self:DoPopulate()
|
||||
|
||||
copy.PropPanel = self.PropPanel:Copy()
|
||||
|
||||
copy.PropPanel:SetVisible( false )
|
||||
copy.PropPanel:SetTriggerSpawnlistChange( true )
|
||||
|
||||
copy.DoPopulate = function() end
|
||||
|
||||
end
|
||||
|
||||
if ( !node.AddonSpawnlist ) then
|
||||
node.OnModified = function()
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end
|
||||
|
||||
node.DoRightClick = function( self )
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.edit", function() self:InternalDoClick() hook.Run( "OpenToolbox" ) end ):SetIcon( "icon16/folder_edit.png" )
|
||||
menu:AddOption( "#spawnmenu.menu.add_subcategory", function() AddCustomizableNode( pnlContent, "New Category", "", self ) self:SetExpanded( true ) hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/folder_add.png" )
|
||||
menu:AddSpacer()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function() node:Remove() hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/folder_delete.png" )
|
||||
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
if ( IsValid( self.PropPanel ) ) then return end
|
||||
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( true )
|
||||
|
||||
end
|
||||
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
AddCustomizableNode = function( pnlContent, name, icon, parent, needsapp )
|
||||
|
||||
local node = parent:AddNode( name, icon )
|
||||
node.AddonSpawnlist = parent.AddonSpawnlist
|
||||
|
||||
SetupCustomNode( node, pnlContent, needsapp )
|
||||
|
||||
return node
|
||||
|
||||
end
|
||||
|
||||
local function ReadSpawnlists( node, parentid )
|
||||
|
||||
local tab = {}
|
||||
tab.name = node:GetText()
|
||||
tab.icon = node:GetIcon()
|
||||
tab.parentid = parentid
|
||||
tab.id = SPAWNLIST_ID
|
||||
tab.version = 3
|
||||
tab.needsapp = node.NeedsApp
|
||||
|
||||
node:DoPopulate()
|
||||
|
||||
if ( IsValid( node.PropPanel ) ) then
|
||||
tab.contents = node.PropPanel:ContentsToTable()
|
||||
end
|
||||
|
||||
if ( SPAWNLIST_ID > 0 ) then
|
||||
SPAWNLISTS[ string.format( "%03d", tab.id ) .. "-" .. tab.name ] = util.TableToKeyValues( tab )
|
||||
end
|
||||
|
||||
SPAWNLIST_ID = SPAWNLIST_ID + 1
|
||||
|
||||
if ( node.ChildNodes ) then
|
||||
|
||||
for k, v in ipairs( node.ChildNodes:GetChildren() ) do
|
||||
|
||||
ReadSpawnlists( v, tab.id )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function ConstructSpawnlist( node )
|
||||
|
||||
SPAWNLIST_ID = 0
|
||||
SPAWNLISTS = {}
|
||||
|
||||
ReadSpawnlists( node, 0 )
|
||||
local tab = SPAWNLISTS
|
||||
|
||||
SPAWNLISTS = nil
|
||||
SPAWNLIST_ID = nil
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
function AddPropsOfParent( pnlContent, node, parentid, customProps )
|
||||
|
||||
local Props = customProps or spawnmenu.GetPropTable()
|
||||
|
||||
for FileName, Info in SortedPairs( Props ) do
|
||||
|
||||
if ( parentid != Info.parentid ) then continue end
|
||||
|
||||
local pnlnode = AddCustomizableNode( pnlContent, Info.name, Info.icon, node, Info.needsapp )
|
||||
pnlnode:SetExpanded( true )
|
||||
pnlnode.OnRemove = function( self ) if ( IsValid( self.PropPanel ) ) then self.PropPanel:Remove() end end
|
||||
pnlnode.DoPopulate = function( self )
|
||||
|
||||
if ( IsValid( self.PropPanel ) ) then return end
|
||||
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( true )
|
||||
if ( node.AddonSpawnlist ) then self.PropPanel.IconList:SetReadOnly( true ) end
|
||||
|
||||
for i, object in SortedPairs( Info.contents ) do
|
||||
|
||||
local cp = spawnmenu.GetContentType( object.type )
|
||||
if ( cp ) then cp( self.PropPanel, object ) end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
AddPropsOfParent( pnlContent, pnlnode, Info.id, customProps )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- This helps avoid empty spawnlist list when you delete some but the hidden ones remain so the default spawnlists never regenerate
|
||||
-- TODO: Maybe show spawnlists that need games when any spawnlist was changed? Allow to set needed game from in-game?
|
||||
local function CheckIfAnyVisible( node )
|
||||
local pnlContent = node.SMContentPanel
|
||||
|
||||
if ( node:GetChildNodeCount() < 1 ) then
|
||||
spawnmenu.PopulateFromEngineTextFiles()
|
||||
AddPropsOfParent( pnlContent, node, 0 )
|
||||
node:SetExpanded( true )
|
||||
return
|
||||
end
|
||||
|
||||
local visible = 0
|
||||
for id, pnl in pairs( node:GetChildNodes() ) do
|
||||
if ( pnl:IsVisible() ) then visible = visible + 1 end
|
||||
end
|
||||
|
||||
if ( visible < 1 ) then
|
||||
for id, pnl in pairs( node:GetChildNodes() ) do
|
||||
pnl:SetVisible( true )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add( "PopulateContent", "AddCustomContent", function( pnlContent, tree, node )
|
||||
|
||||
local node = AddCustomizableNode( pnlContent, "#spawnmenu.category.your_spawnlists", "", tree )
|
||||
node:SetDraggableName( "CustomContent" )
|
||||
node:SetExpanded( true )
|
||||
node.CustomSpawnlist = nil
|
||||
node.SMContentPanel = pnlContent
|
||||
|
||||
node.DoRightClick = function( self )
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "New Category", function() AddCustomizableNode( pnlContent, "New Category", "", node ) node:SetExpanded( true ) hook.Run( "SpawnlistContentChanged" ) end ):SetIcon( "icon16/folder_add.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
-- Save the spawnlist when children drag and dropped
|
||||
node.OnModified = function()
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end
|
||||
|
||||
AddPropsOfParent( pnlContent, node, 0 )
|
||||
|
||||
CheckIfAnyVisible( node )
|
||||
|
||||
node:MoveToBack()
|
||||
|
||||
g_SpawnMenu.CustomizableSpawnlistNode = node
|
||||
|
||||
-- Select the first visible panel
|
||||
for id, pnl in pairs( node:GetChildNodes() ) do
|
||||
if ( pnl:IsVisible() ) then
|
||||
pnl:InternalDoClick()
|
||||
pnl:SetExpanded( true )
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Custom stuff from addons
|
||||
local CustomProps = spawnmenu.GetCustomPropTable()
|
||||
if ( !table.IsEmpty( CustomProps ) ) then
|
||||
local node = AddCustomizableNode( pnlContent, "#spawnmenu.category.addon_spawnlists", "", tree )
|
||||
node:SetExpanded( true )
|
||||
--node:SetDraggableName( "CustomContent" )
|
||||
node.DoRightClick = function() end
|
||||
node.OnModified = function() end
|
||||
node.AddonSpawnlist = true
|
||||
node.CustomSpawnlist = nil
|
||||
|
||||
AddPropsOfParent( pnlContent, node, 0, CustomProps )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "OnSaveSpawnlist", "DoSaveSpawnlist", function()
|
||||
|
||||
local Spawnlist = ConstructSpawnlist( g_SpawnMenu.CustomizableSpawnlistNode )
|
||||
|
||||
spawnmenu.DoSaveToTextFiles( Spawnlist )
|
||||
|
||||
CheckIfAnyVisible( g_SpawnMenu.CustomizableSpawnlistNode )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "OnRevertSpawnlist", "DoRevertSpawnlists", function()
|
||||
|
||||
-- First delete all of the existing spawnlists
|
||||
g_SpawnMenu.CustomizableSpawnlistNode:Clear()
|
||||
|
||||
-- Next load all the custom spawnlists again
|
||||
spawnmenu.PopulateFromEngineTextFiles()
|
||||
AddPropsOfParent( g_SpawnMenu.CustomizableSpawnlistNode.SMContentPanel, g_SpawnMenu.CustomizableSpawnlistNode, 0 )
|
||||
|
||||
-- Select the first visible panel. TODO: why this requires a timer?
|
||||
timer.Simple( 0, function()
|
||||
CheckIfAnyVisible( g_SpawnMenu.CustomizableSpawnlistNode )
|
||||
|
||||
for id, pnl in pairs( g_SpawnMenu.CustomizableSpawnlistNode:GetChildNodes() ) do
|
||||
if ( pnl:IsVisible() ) then
|
||||
pnl:InternalDoClick()
|
||||
pnl:SetExpanded( true )
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
g_SpawnMenu.CustomizableSpawnlistNode:SetExpanded( true )
|
||||
end )
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,125 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local HTML = nil
|
||||
local DupeInClipboard = false
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.dupes", function()
|
||||
|
||||
HTML = vgui.Create( "DHTML" )
|
||||
JS_Language( HTML )
|
||||
JS_Workshop( HTML )
|
||||
|
||||
ws_dupe = WorkshopFileBase( "dupe", { "dupe" } )
|
||||
ws_dupe.HTML = HTML
|
||||
|
||||
function ws_dupe:FetchLocal( offset, perpage )
|
||||
|
||||
local f = file.Find( "dupes/*.dupe", "MOD", "datedesc" )
|
||||
|
||||
local saves = {}
|
||||
|
||||
for k, v in ipairs( f ) do
|
||||
|
||||
if ( k <= offset ) then continue end
|
||||
if ( k > offset + perpage ) then break end
|
||||
|
||||
local entry = {
|
||||
file = "dupes/" .. v,
|
||||
name = v:StripExtension(),
|
||||
preview = "dupes/" .. v:StripExtension() .. ".jpg",
|
||||
description = "Local duplication stored on your computer. Local content can be deleted in the main menu."
|
||||
}
|
||||
|
||||
table.insert( saves, entry )
|
||||
|
||||
end
|
||||
|
||||
local results = {
|
||||
totalresults = #f,
|
||||
results = saves
|
||||
}
|
||||
|
||||
local json = util.TableToJSON( results, false )
|
||||
HTML:Call( "dupe.ReceiveLocal( " .. json .. " )" )
|
||||
|
||||
end
|
||||
|
||||
function ws_dupe:Arm( filename )
|
||||
|
||||
RunConsoleCommand( "dupe_arm", filename )
|
||||
|
||||
end
|
||||
|
||||
function ws_dupe:DownloadAndArm( id )
|
||||
|
||||
-- Server doesn't allow us to arm dupes, don't even try to download anything
|
||||
local res, msg = hook.Run( "CanArmDupe", LocalPlayer() )
|
||||
if ( res == false ) then LocalPlayer():ChatPrint( msg or "Refusing to download Workshop dupe, server has blocked usage of the Duplicator tool!" ) return end
|
||||
|
||||
MsgN( "Downloading Dupe..." )
|
||||
steamworks.DownloadUGC( id, function( name )
|
||||
|
||||
MsgN( "Finished - arming!" )
|
||||
ws_dupe:Arm( name )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function ws_dupe:Publish( filename, imagename )
|
||||
|
||||
RunConsoleCommand( "dupe_publish", filename, imagename )
|
||||
|
||||
end
|
||||
|
||||
HTML:OpenURL( "asset://garrysmod/html/dupes.html" )
|
||||
HTML:Call( "SetDupeSaveState( " .. tostring( DupeInClipboard ) .. " );" )
|
||||
|
||||
return HTML
|
||||
|
||||
end, "icon16/control_repeat_blue.png", 200 )
|
||||
|
||||
hook.Add( "DupeSaveAvailable", "UpdateDupeSpawnmenuAvailable", function()
|
||||
|
||||
DupeInClipboard = true
|
||||
|
||||
if ( !IsValid( HTML ) ) then return end
|
||||
|
||||
HTML:Call( "SetDupeSaveState( true );" )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "DupeSaveUnavailable", "UpdateDupeSpawnmenuUnavailable", function()
|
||||
|
||||
DupeInClipboard = false
|
||||
|
||||
if ( !IsValid( HTML ) ) then return end
|
||||
|
||||
HTML:Call( "SetDupeSaveState( false );" )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "DupeSaved", "DuplicationSavedSpawnMenu", function()
|
||||
|
||||
if ( !IsValid( HTML ) ) then return end
|
||||
|
||||
HTML:Call( "ShowLocalDupes();" )
|
||||
|
||||
end )
|
||||
|
||||
concommand.Add( "dupe_show", function()
|
||||
|
||||
g_SpawnMenu:OpenCreationMenuTab( "#spawnmenu.category.dupes" )
|
||||
|
||||
timer.Simple( 1.0, function() if ( !IsValid( HTML ) ) then return end HTML:Call( "ShowLocalDupes();" ) end )
|
||||
|
||||
end, nil, "", { FCVAR_DONTRECORD } )
|
||||
@@ -0,0 +1,94 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
list.Set( "ContentCategoryIcons", "Half-Life: Source", "games/16/hl1.png" )
|
||||
list.Set( "ContentCategoryIcons", "Half-Life 2", "games/16/hl2.png" )
|
||||
list.Set( "ContentCategoryIcons", "Portal", "games/16/portal.png" )
|
||||
|
||||
hook.Add( "PopulateEntities", "AddEntityContent", function( pnlContent, tree, browseNode )
|
||||
|
||||
local Categorised = {}
|
||||
|
||||
-- Add this list into the tormoil
|
||||
local SpawnableEntities = list.Get( "SpawnableEntities" )
|
||||
if ( SpawnableEntities ) then
|
||||
for k, v in pairs( SpawnableEntities ) do
|
||||
|
||||
local Category = v.Category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
Categorised[ Category ] = Categorised[ Category ] or {}
|
||||
|
||||
v.SpawnName = k
|
||||
table.insert( Categorised[ Category ], v )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Add a tree node for each category
|
||||
--
|
||||
local CustomIcons = list.Get( "ContentCategoryIcons" )
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, CustomIcons[ CategoryName ] or "icon16/bricks.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for k, ent in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "entity", self.PropPanel, {
|
||||
nicename = ent.PrintName or ent.ClassName,
|
||||
spawnname = ent.SpawnName,
|
||||
material = ent.IconOverride or "entities/" .. ent.SpawnName .. ".png",
|
||||
admin = ent.AdminOnly
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.entities", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:EnableSearch( "entities", "PopulateEntities" )
|
||||
ctrl:CallPopulateHook( "PopulateEntities" )
|
||||
|
||||
return ctrl
|
||||
|
||||
end, "icon16/bricks.png", 20 )
|
||||
@@ -0,0 +1,188 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local function recurseAddFiles( folder, pathid, list )
|
||||
|
||||
local addedLabel = false
|
||||
|
||||
local files, folders = file.Find( folder .. "/*", pathid )
|
||||
for id, file in pairs( files or {} ) do
|
||||
if ( file:EndsWith( ".mdl" ) ) then
|
||||
if ( !addedLabel ) then
|
||||
table.insert( list, { type = "header", text = folder } )
|
||||
addedLabel = true
|
||||
end
|
||||
|
||||
table.insert( list, { type = "model", model = folder .. "/" .. file } )
|
||||
end
|
||||
end
|
||||
|
||||
for id, fold in pairs( folders or {} ) do
|
||||
recurseAddFiles( folder .. "/" .. fold, pathid, list )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function GenerateSpawnlistFromPath( folder, path, name, icon, appid )
|
||||
|
||||
local contents = {}
|
||||
recurseAddFiles( folder, path, contents )
|
||||
|
||||
AddPropsOfParent( g_SpawnMenu.CustomizableSpawnlistNode.SMContentPanel, g_SpawnMenu.CustomizableSpawnlistNode, 0, { [ folder ] = {
|
||||
icon = icon or "icon16/page.png",
|
||||
id = math.random( 0, 999999 ), -- Eeehhhh
|
||||
name = name or folder,
|
||||
parentid = 0,
|
||||
needsapp = appid,
|
||||
contents = contents
|
||||
} } )
|
||||
|
||||
-- We added a new spawnlist, show the save changes button
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
|
||||
end
|
||||
|
||||
local function GamePropsRightClick( self )
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.createautospawnlist", function()
|
||||
|
||||
-- Find the "root" node for this game
|
||||
local parent = self
|
||||
local icon = parent:GetIcon()
|
||||
while ( !icon:StartsWith( "games" ) ) do
|
||||
parent = parent:GetParentNode()
|
||||
if ( !IsValid( parent ) ) then break end
|
||||
icon = parent:GetIcon()
|
||||
end
|
||||
|
||||
local name = parent:GetText()
|
||||
if ( self:GetFolder() != "models" ) then
|
||||
name = name .. " - " .. self:GetFolder():sub( 8 )
|
||||
end
|
||||
|
||||
GenerateSpawnlistFromPath( self:GetFolder(), self:GetPathID(), name, icon, parent.GamePathID )
|
||||
|
||||
end ):SetIcon( "icon16/page_add.png" )
|
||||
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
local function InstallNodeRightclick( self, newNode )
|
||||
newNode.DoRightClick = GamePropsRightClick
|
||||
newNode.OnNodeAdded = InstallNodeRightclick
|
||||
end
|
||||
|
||||
local function AddBrowseContent( ViewPanel, node, name, icon, path, pathid, pnlContent )
|
||||
|
||||
local models = node:AddFolder( name, path .. "models", pathid, false )
|
||||
models:SetIcon( icon )
|
||||
models.BrowseContentType = "models"
|
||||
models.BrowseExtension = "*.mdl"
|
||||
models.ContentType = "model"
|
||||
models.ViewPanel = ViewPanel
|
||||
models.GamePathID = pathid
|
||||
|
||||
-- If we click on a subnode of this tree, it gets reported upwards (to us)
|
||||
models.OnNodeSelected = function( slf, node )
|
||||
|
||||
-- Already viewing this panel
|
||||
if ( ViewPanel && ViewPanel.CurrentNode && ViewPanel.CurrentNode == node ) then
|
||||
if ( pnlContent.SelectedPanel != ViewPanel ) then pnlContent:SwitchPanel( ViewPanel ) end
|
||||
return
|
||||
end
|
||||
|
||||
-- Clear the viewpanel in preperation for displaying it
|
||||
ViewPanel:Clear()
|
||||
ViewPanel.CurrentNode = node
|
||||
|
||||
-- Fill the viewpanel with models that are in this node's folder
|
||||
local node_path = node:GetFolder()
|
||||
local SearchString = node_path .. "/*.mdl"
|
||||
|
||||
local mdls = file.Find( SearchString, node:GetPathID() )
|
||||
if ( mdls ) then
|
||||
for k, v in ipairs( mdls ) do
|
||||
local cp = spawnmenu.GetContentType( "model" )
|
||||
if ( cp ) then
|
||||
cp( ViewPanel, { model = node_path .. "/" .. v } )
|
||||
end
|
||||
end
|
||||
else
|
||||
MsgN( "Warning! Not opening '" .. node_path .. "' because we cannot search in it!" )
|
||||
end
|
||||
|
||||
-- Switch to it
|
||||
pnlContent:SwitchPanel( ViewPanel )
|
||||
ViewPanel.CurrentNode = node
|
||||
|
||||
end
|
||||
|
||||
InstallNodeRightclick( node, models )
|
||||
|
||||
end
|
||||
|
||||
local function RefreshGames( MyNode )
|
||||
|
||||
local games = engine.GetGames()
|
||||
table.insert( games, {
|
||||
title = "All",
|
||||
folder = "GAME",
|
||||
icon = "all",
|
||||
mounted = true
|
||||
} )
|
||||
table.insert( games, {
|
||||
title = "Garry's Mod",
|
||||
folder = "garrysmod",
|
||||
mounted = true
|
||||
} )
|
||||
|
||||
-- Create a list of mounted games, allowing us to browse them
|
||||
for _, game in SortedPairsByMemberValue( games, "title" ) do
|
||||
|
||||
if ( !game.mounted ) then continue end
|
||||
|
||||
AddBrowseContent( MyNode.ViewPanel, MyNode, game.title, "games/16/" .. ( game.icon or game.folder ) .. ".png", "", game.folder, MyNode.pnlContent )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Called when setting up the sidebar on the spawnmenu - to populate the tree
|
||||
local myGamesNode
|
||||
hook.Add( "PopulateContent", "GameProps", function( pnlContent, tree, node )
|
||||
|
||||
-- Create a node in the `other` category on the tree
|
||||
myGamesNode = node:AddNode( "#spawnmenu.category.games", "icon16/folder_database.png" )
|
||||
myGamesNode.pnlContent = pnlContent
|
||||
|
||||
local ViewPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
ViewPanel:SetVisible( false )
|
||||
ViewPanel.IconList:SetReadOnly( true )
|
||||
myGamesNode.ViewPanel = ViewPanel
|
||||
|
||||
RefreshGames( myGamesNode )
|
||||
|
||||
end )
|
||||
|
||||
|
||||
hook.Add( "GameContentChanged", "RefreshSpawnmenuGames", function()
|
||||
|
||||
if ( !IsValid( myGamesNode ) ) then return end
|
||||
|
||||
-- TODO: Maybe be more advaced and do not delete => recreate all the nodes, only delete nodes for addons that were removed, add only the new ones?
|
||||
myGamesNode:Clear()
|
||||
myGamesNode.ViewPanel:Clear()
|
||||
|
||||
RefreshGames( myGamesNode )
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,159 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
hook.Add( "PopulateNPCs", "AddNPCContent", function( pnlContent, tree, browseNode )
|
||||
|
||||
-- Get a list of available NPCs
|
||||
local NPCList = list.Get( "NPC" )
|
||||
|
||||
-- Categorize them
|
||||
local Categories = {}
|
||||
for k, v in pairs( NPCList ) do
|
||||
|
||||
local Category = v.Category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
|
||||
local Tab = Categories[ Category ] or {}
|
||||
Tab[ k ] = v
|
||||
Categories[ Category ] = Tab
|
||||
|
||||
end
|
||||
|
||||
-- Create an icon for each one and put them on the panel
|
||||
local CustomIcons = list.Get( "ContentCategoryIcons" )
|
||||
for CategoryName, v in SortedPairs( Categories ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, CustomIcons[ CategoryName ] or "icon16/monkey.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for name, ent in SortedPairsByMemberValue( v, "Name" ) do
|
||||
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "npc", self.PropPanel, {
|
||||
nicename = ent.Name or name,
|
||||
spawnname = name,
|
||||
material = ent.IconOverride or "entities/" .. name .. ".png",
|
||||
weapon = ent.Weapons,
|
||||
admin = ent.AdminOnly
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
Derma_Hook( PANEL, "Paint", "Paint", "Tree" )
|
||||
PANEL.m_bBackground = true -- Hack for above
|
||||
|
||||
function PANEL:AddCheckbox( text, cvar )
|
||||
local DermaCheckbox = self:Add( "DCheckBoxLabel", self )
|
||||
DermaCheckbox:Dock( TOP )
|
||||
DermaCheckbox:SetText( text )
|
||||
DermaCheckbox:SetDark( true )
|
||||
DermaCheckbox:SetConVar( cvar)
|
||||
DermaCheckbox:SizeToContents()
|
||||
DermaCheckbox:DockMargin( 0, 5, 0, 0 )
|
||||
end
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetOpenSize( 150 )
|
||||
self:DockPadding( 15, 10, 15, 10 )
|
||||
|
||||
self:AddCheckbox( "#menubar.npcs.disableai", "ai_disabled" )
|
||||
self:AddCheckbox( "#menubar.npcs.ignoreplayers", "ai_ignoreplayers" )
|
||||
self:AddCheckbox( "#menubar.npcs.keepcorpses", "ai_serverragdolls" )
|
||||
self:AddCheckbox( "#menubar.npcs.autoplayersquad", "npc_citizen_auto_player_squad" )
|
||||
|
||||
local label = vgui.Create( "DLabel", self )
|
||||
label:Dock( TOP )
|
||||
label:DockMargin( 0, 5, 0, 0 )
|
||||
label:SetDark( true )
|
||||
label:SetText( "#menubar.npcs.weapon" )
|
||||
|
||||
local DComboBox = vgui.Create( "DComboBox", self )
|
||||
DComboBox:Dock( TOP )
|
||||
DComboBox:DockMargin( 0, 0, 0, 0 )
|
||||
DComboBox:SetConVar( "gmod_npcweapon" )
|
||||
DComboBox:SetSortItems( false )
|
||||
|
||||
DComboBox:AddChoice( "#menubar.npcs.defaultweapon", "" )
|
||||
DComboBox:AddChoice( "#menubar.npcs.noweapon", "none" )
|
||||
|
||||
-- Sort the items by name, and group by category
|
||||
local groupedWeps = {}
|
||||
for _, v in pairs( list.Get( "NPCUsableWeapons" ) ) do
|
||||
local cat = (v.category or ""):lower()
|
||||
groupedWeps[ cat ] = groupedWeps[ cat ] or {}
|
||||
groupedWeps[ cat ][ v.class ] = language.GetPhrase( v.title )
|
||||
end
|
||||
|
||||
for group, items in SortedPairs( groupedWeps ) do
|
||||
DComboBox:AddSpacer()
|
||||
for class, title in SortedPairsByValue( items ) do
|
||||
DComboBox:AddChoice( title, class )
|
||||
end
|
||||
end
|
||||
|
||||
function DComboBox:OnSelect( index, value )
|
||||
self:ConVarChanged( self.Data[ index ] )
|
||||
end
|
||||
|
||||
self:Open()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
end
|
||||
|
||||
vgui.Register( "SpawnmenuNPCSidebarToolbox", PANEL, "DDrawer" )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.npcs", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:EnableSearch( "npcs", "PopulateNPCs" )
|
||||
ctrl:CallPopulateHook( "PopulateNPCs" )
|
||||
|
||||
local sidebar = ctrl.ContentNavBar
|
||||
sidebar.Options = vgui.Create( "SpawnmenuNPCSidebarToolbox", sidebar )
|
||||
|
||||
return ctrl
|
||||
|
||||
end, "icon16/monkey.png", 20 )
|
||||
@@ -0,0 +1,93 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
hook.Add( "PopulatePostProcess", "AddPostProcess", function( pnlContent, tree, node )
|
||||
|
||||
-- Get a list of postproceess effects
|
||||
-- and organise them into categories
|
||||
local Categorised = {}
|
||||
local PostProcess = list.Get( "PostProcess" )
|
||||
|
||||
if ( PostProcess ) then
|
||||
|
||||
for k, v in pairs( PostProcess ) do
|
||||
|
||||
local Category = v.category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
Categorised[ Category ] = Categorised[ Category ] or {}
|
||||
|
||||
v.name = k
|
||||
table.insert( Categorised[ Category ], v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Create an entry for each category
|
||||
--
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, "icon16/picture.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for k, pp in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
|
||||
if ( pp.func ) then
|
||||
pp.func( self.PropPanel )
|
||||
continue
|
||||
end
|
||||
|
||||
spawnmenu.CreateContentIcon( "postprocess", self.PropPanel, {
|
||||
name = pp.name,
|
||||
icon = pp.icon
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.postprocess", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:CallPopulateHook( "PopulatePostProcess" )
|
||||
return ctrl
|
||||
|
||||
end, "icon16/picture.png", 100 )
|
||||
@@ -0,0 +1,81 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local HTML = nil
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.saves", function()
|
||||
|
||||
HTML = vgui.Create( "DHTML" )
|
||||
JS_Language( HTML )
|
||||
JS_Workshop( HTML )
|
||||
|
||||
ws_save = WorkshopFileBase( "save", { "save" } )
|
||||
ws_save.HTML = HTML
|
||||
|
||||
function ws_save:FetchLocal( offset, perpage )
|
||||
|
||||
local f = file.Find( "saves/*.gms", "MOD", "datedesc" )
|
||||
|
||||
local saves = {}
|
||||
|
||||
for k, v in ipairs( f ) do
|
||||
|
||||
if ( k <= offset ) then continue end
|
||||
if ( k > offset + perpage ) then break end
|
||||
|
||||
local entry = {
|
||||
file = "saves/" .. v,
|
||||
name = v:StripExtension(),
|
||||
preview = "saves/" .. v:StripExtension() .. ".jpg",
|
||||
description = "Local map saves stored on your computer. Local content can be deleted in the main menu."
|
||||
}
|
||||
|
||||
table.insert( saves, entry )
|
||||
|
||||
end
|
||||
|
||||
local results = {
|
||||
totalresults = #f,
|
||||
results = saves
|
||||
}
|
||||
|
||||
local json = util.TableToJSON( results, false )
|
||||
HTML:Call( "save.ReceiveLocal( " .. json .. " )" )
|
||||
|
||||
end
|
||||
|
||||
function ws_save:DownloadAndLoad( id )
|
||||
|
||||
steamworks.DownloadUGC( id, function( name )
|
||||
|
||||
ws_save:Load( name )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function ws_save:Load( filename ) RunConsoleCommand( "gm_load", filename ) end
|
||||
function ws_save:Publish( filename, imagename ) RunConsoleCommand( "save_publish", filename, imagename ) end
|
||||
|
||||
HTML:OpenURL( "asset://garrysmod/html/saves.html" )
|
||||
HTML:Call( "SetMap( '" .. game.GetMap() .. "' );" )
|
||||
|
||||
return HTML
|
||||
|
||||
end, "icon16/disk_multiple.png", 200 )
|
||||
|
||||
hook.Add( "PostGameSaved", "OnCreationsSaved", function()
|
||||
|
||||
if ( !HTML ) then return end
|
||||
|
||||
HTML:Call( "OnGameSaved()" )
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,91 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
hook.Add( "PopulateVehicles", "AddEntityContent", function( pnlContent, tree, browseNode )
|
||||
|
||||
local Categorised = {}
|
||||
|
||||
-- Add this list into the tormoil
|
||||
local Vehicles = list.Get( "Vehicles" )
|
||||
if ( Vehicles ) then
|
||||
for k, v in pairs( Vehicles ) do
|
||||
|
||||
local Category = v.Category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
Categorised[ Category ] = Categorised[ Category ] or {}
|
||||
|
||||
v.ClassName = k
|
||||
v.PrintName = v.Name
|
||||
v.ScriptedEntityType = "vehicle"
|
||||
table.insert( Categorised[ Category ], v )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Add a tree node for each category
|
||||
--
|
||||
local CustomIcons = list.Get( "ContentCategoryIcons" )
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, CustomIcons[ CategoryName ] or "icon16/bricks.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for k, ent in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "entity", self.PropPanel, {
|
||||
nicename = ent.PrintName or ent.ClassName,
|
||||
spawnname = ent.ClassName,
|
||||
material = ent.IconOverride or "entities/" .. ent.ClassName .. ".png",
|
||||
admin = ent.AdminOnly
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.vehicles", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:EnableSearch( "vehicles", "PopulateVehicles" )
|
||||
ctrl:CallPopulateHook( "PopulateVehicles" )
|
||||
return ctrl
|
||||
|
||||
end, "icon16/car.png", 50 )
|
||||
@@ -0,0 +1,87 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
hook.Add( "PopulateWeapons", "AddWeaponContent", function( pnlContent, tree, browseNode )
|
||||
|
||||
-- Loop through the weapons and add them to the menu
|
||||
local Weapons = list.Get( "Weapon" )
|
||||
local Categorised = {}
|
||||
|
||||
-- Build into categories
|
||||
for k, weapon in pairs( Weapons ) do
|
||||
|
||||
if ( !weapon.Spawnable ) then continue end
|
||||
|
||||
local Category = weapon.Category or "Other"
|
||||
if ( !isstring( Category ) ) then Category = tostring( Category ) end
|
||||
|
||||
Categorised[ Category ] = Categorised[ Category ] or {}
|
||||
table.insert( Categorised[ Category ], weapon )
|
||||
|
||||
end
|
||||
|
||||
-- Loop through each category
|
||||
local CustomIcons = list.Get( "ContentCategoryIcons" )
|
||||
for CategoryName, v in SortedPairs( Categorised ) do
|
||||
|
||||
-- Add a node to the tree
|
||||
local node = tree:AddNode( CategoryName, CustomIcons[ CategoryName ] or "icon16/gun.png" )
|
||||
|
||||
-- When we click on the node - populate it using this function
|
||||
node.DoPopulate = function( self )
|
||||
|
||||
-- If we've already populated it - forget it.
|
||||
if ( self.PropPanel ) then return end
|
||||
|
||||
-- Create the container panel
|
||||
self.PropPanel = vgui.Create( "ContentContainer", pnlContent )
|
||||
self.PropPanel:SetVisible( false )
|
||||
self.PropPanel:SetTriggerSpawnlistChange( false )
|
||||
|
||||
for k, ent in SortedPairsByMemberValue( v, "PrintName" ) do
|
||||
|
||||
spawnmenu.CreateContentIcon( ent.ScriptedEntityType or "weapon", self.PropPanel, {
|
||||
nicename = ent.PrintName or ent.ClassName,
|
||||
spawnname = ent.ClassName,
|
||||
material = ent.IconOverride or "entities/" .. ent.ClassName .. ".png",
|
||||
admin = ent.AdminOnly
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- If we click on the node populate it and switch to it.
|
||||
node.DoClick = function( self )
|
||||
|
||||
self:DoPopulate()
|
||||
pnlContent:SwitchPanel( self.PropPanel )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Select the first node
|
||||
local FirstNode = tree:Root():GetChildNode( 0 )
|
||||
if ( IsValid( FirstNode ) ) then
|
||||
FirstNode:InternalDoClick()
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
spawnmenu.AddCreationTab( "#spawnmenu.category.weapons", function()
|
||||
|
||||
local ctrl = vgui.Create( "SpawnmenuContentPanel" )
|
||||
ctrl:EnableSearch( "weapons", "PopulateWeapons" )
|
||||
ctrl:CallPopulateHook( "PopulateWeapons" )
|
||||
return ctrl
|
||||
|
||||
end, "icon16/gun.png", 10 )
|
||||
@@ -0,0 +1,192 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self:SetPaintBackground( false )
|
||||
self:SetSize( 128, 128 )
|
||||
self:SetText( "" )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnDepressionChanged( b )
|
||||
|
||||
if ( IsValid( self.checkbox ) ) then
|
||||
self.checkbox:SetVisible( !b )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Setup( name, icon, label )
|
||||
|
||||
self.label = label
|
||||
self.name = name
|
||||
self.icon = icon
|
||||
|
||||
self:SetMaterial( icon )
|
||||
self:SetName( label or name )
|
||||
|
||||
self.PP = list.Get( "PostProcess" )[ name ]
|
||||
if ( !self.PP ) then return end
|
||||
|
||||
self.DoClick = function()
|
||||
|
||||
if ( self.PP.onclick ) then
|
||||
return self.PP.onclick()
|
||||
end
|
||||
|
||||
if ( !self.PP.cpanel ) then return end
|
||||
|
||||
if ( !IsValid( self.cp ) ) then
|
||||
|
||||
self.cp = vgui.Create( "ControlPanel" )
|
||||
self.cp:SetName( name )
|
||||
self.PP.cpanel( self.cp )
|
||||
|
||||
end
|
||||
|
||||
spawnmenu.ActivateToolPanel( 1, self.cp )
|
||||
|
||||
end
|
||||
|
||||
if ( self.PP.convar ) then
|
||||
|
||||
self.checkbox = self:Add( "DCheckBox" )
|
||||
self.checkbox:SetConVar( self.PP.convar )
|
||||
self.checkbox:SetSize( 20, 20 )
|
||||
self.checkbox:SetPos( self:GetWide() - 20 - 8, 8 )
|
||||
|
||||
self.Enabled = function() return self.checkbox:GetChecked() end
|
||||
|
||||
elseif ( self.ConVars ) then
|
||||
|
||||
self.checkbox = self:Add( "DCheckBox" )
|
||||
self.checkbox:SetSize( 20, 20 )
|
||||
self.checkbox:SetPos( self:GetWide() - 20 - 8, 8 )
|
||||
|
||||
self.checkbox.OnChange = function( pnl, on )
|
||||
|
||||
for k, v in pairs( self.ConVars ) do
|
||||
|
||||
if ( on ) then
|
||||
RunConsoleCommand( k, v.on )
|
||||
else
|
||||
RunConsoleCommand( k, v.off or "" )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.checkbox.Think = function( pnl, on )
|
||||
|
||||
local good = true
|
||||
|
||||
for k, v in pairs( self.ConVars ) do
|
||||
|
||||
if ( GetConVarString( k ) != v.on ) then
|
||||
good = false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
pnl:SetChecked( good )
|
||||
|
||||
end
|
||||
|
||||
self.Enabled = function() return self.checkbox:GetChecked() end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoRightClick()
|
||||
|
||||
local pCanvas = self:GetSelectionCanvas()
|
||||
if ( IsValid( pCanvas ) && pCanvas:NumSelectedChildren() > 0 && self:IsSelected() ) then
|
||||
return hook.Run( "SpawnlistOpenGenericMenu", pCanvas )
|
||||
end
|
||||
|
||||
self:OpenMenu()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:DoClick()
|
||||
end
|
||||
|
||||
function PANEL:OpenMenu()
|
||||
|
||||
-- Do not allow removal from read only panels
|
||||
if ( IsValid( self:GetParent() ) && self:GetParent().GetReadOnly && self:GetParent():GetReadOnly() ) then return end
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu:AddOption( "#spawnmenu.menu.delete", function()
|
||||
self:Remove()
|
||||
hook.Run( "SpawnlistContentChanged" )
|
||||
end ):SetIcon( "icon16/bin_closed.png" )
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Enabled()
|
||||
return false
|
||||
end
|
||||
|
||||
function PANEL:ToTable( bigtable )
|
||||
|
||||
local tab = {}
|
||||
|
||||
tab.type = "postprocess"
|
||||
tab.name = self.name
|
||||
tab.label = self.label
|
||||
tab.icon = self.icon
|
||||
tab.convars = self.ConVars
|
||||
|
||||
table.insert( bigtable, tab )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Copy()
|
||||
|
||||
local copy = vgui.Create( "PostProcessIcon", self:GetParent() )
|
||||
copy:CopyBounds( self )
|
||||
copy.ConVars = self.ConVars
|
||||
copy:Setup( self.name, self.icon, self.label )
|
||||
|
||||
return copy
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "PostProcessIcon", PANEL, "ContentIcon" )
|
||||
|
||||
spawnmenu.AddContentType( "postprocess", function( container, obj )
|
||||
|
||||
if ( !obj.name ) then return end
|
||||
if ( !obj.icon ) then return end
|
||||
|
||||
local icon = vgui.Create( "PostProcessIcon", container )
|
||||
|
||||
if ( obj.convars ) then
|
||||
icon.ConVars = obj.convars
|
||||
end
|
||||
|
||||
icon:Setup( obj.name, obj.icon, obj.label )
|
||||
|
||||
container:Add( icon )
|
||||
|
||||
return icon
|
||||
|
||||
end )
|
||||
@@ -0,0 +1,12 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
include( "content/content.lua" )
|
||||
43
gamemodes/sandbox/gamemode/spawnmenu/init.lua
Normal file
43
gamemodes/sandbox/gamemode/spawnmenu/init.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
--[[
|
||||
| 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( "sandbox/gamemode/spawnmenu/controls/manifest.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/control_presets.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/preset_editor.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/ropematerial.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/ctrlnumpad.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/ctrlcolor.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controls/ctrllistbox.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/contextmenu.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/spawnmenu.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/toolmenu.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/controlpanel.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/toolpanel.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/manifest.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/content.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentcontainer.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentheader.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenticon.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentsearch.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentsidebar.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contentsidebartoolbox.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/postprocessicon.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/addonprops.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/custom.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/entities.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/gameprops.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/npcs.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/postprocess.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/weapons.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/vehicles.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/saves.lua" )
|
||||
AddCSLuaFile( "sandbox/gamemode/spawnmenu/creationmenu/content/contenttypes/dupes.lua" )
|
||||
406
gamemodes/sandbox/gamemode/spawnmenu/spawnmenu.lua
Normal file
406
gamemodes/sandbox/gamemode/spawnmenu/spawnmenu.lua
Normal file
@@ -0,0 +1,406 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local spawnmenu_border = CreateConVar( "spawnmenu_border", "0.1", { FCVAR_ARCHIVE }, "Amount of empty space around the Sandbox spawn menu." )
|
||||
|
||||
include( "toolmenu.lua" )
|
||||
include( "contextmenu.lua" )
|
||||
include( "creationmenu.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:Dock( FILL )
|
||||
|
||||
self.HorizontalDivider = vgui.Create( "DHorizontalDivider", self )
|
||||
self.HorizontalDivider:Dock( FILL )
|
||||
self.HorizontalDivider:SetLeftWidth( ScrW() ) -- It will be automatically resized by DHorizontalDivider to account for GetRightMin/GetLeftMin
|
||||
self.HorizontalDivider:SetDividerWidth( 6 )
|
||||
self.HorizontalDivider:SetCookieName( "SpawnMenuDiv" )
|
||||
self.HorizontalDivider:SetRightMin( 300 )
|
||||
if ( ScrW() >= 1024 ) then self.HorizontalDivider:SetRightMin( 460 ) end
|
||||
|
||||
self.ToolMenu = vgui.Create( "ToolMenu", self.HorizontalDivider )
|
||||
self.HorizontalDivider:SetRight( self.ToolMenu )
|
||||
|
||||
self.CreateMenu = vgui.Create( "CreationMenu", self.HorizontalDivider )
|
||||
self.HorizontalDivider:SetLeft( self.CreateMenu )
|
||||
|
||||
self.m_bHangOpen = false
|
||||
|
||||
self:SetMouseInputEnabled( true )
|
||||
|
||||
self.ToolToggle = vgui.Create( "DImageButton", self )
|
||||
self.ToolToggle:SetImage( "gui/spawnmenu_toggle" )
|
||||
self.ToolToggle:SetSize( 16, 16 )
|
||||
self.ToolToggle.DoClick = function()
|
||||
|
||||
self.ToolMenu:SetVisible( !self.ToolMenu:IsVisible() )
|
||||
self:InvalidateLayout()
|
||||
|
||||
if ( self.ToolMenu:IsVisible() ) then
|
||||
self.ToolToggle:SetImage( "gui/spawnmenu_toggle" )
|
||||
self.CreateMenu:Dock( NODOCK ) -- What an ugly hack
|
||||
self.HorizontalDivider:SetRight( self.ToolMenu )
|
||||
self.HorizontalDivider:SetLeft( self.CreateMenu )
|
||||
else
|
||||
self.ToolToggle:SetImage( "gui/spawnmenu_toggle_back" )
|
||||
self.HorizontalDivider:SetRight( nil ) -- What an ugly hack
|
||||
self.HorizontalDivider:SetLeft( nil )
|
||||
self.CreateMenu:SetParent( self.HorizontalDivider )
|
||||
self.CreateMenu:Dock( FILL )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OpenCreationMenuTab( name )
|
||||
|
||||
self.CreateMenu:SwitchToName( name )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetToolMenu()
|
||||
|
||||
return self.ToolMenu
|
||||
|
||||
end
|
||||
|
||||
function PANEL:GetCreationMenu()
|
||||
|
||||
return self.CreateMenu
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: OnClick
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:OnMousePressed()
|
||||
|
||||
self:Close()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HangOpen
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:HangOpen( bHang )
|
||||
|
||||
self.m_bHangOpen = bHang
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HangingOpen
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:HangingOpen()
|
||||
|
||||
return self.m_bHangOpen
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Open()
|
||||
|
||||
RestoreCursorPosition()
|
||||
|
||||
self.m_bHangOpen = false
|
||||
|
||||
-- If the context menu is open, try to close it..
|
||||
if ( IsValid( g_ContextMenu ) && g_ContextMenu:IsVisible() ) then
|
||||
g_ContextMenu:Close( true )
|
||||
end
|
||||
|
||||
if ( self:IsVisible() ) then return end
|
||||
|
||||
CloseDermaMenus()
|
||||
|
||||
self:MakePopup()
|
||||
self:SetVisible( true )
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
self:SetMouseInputEnabled( true )
|
||||
self:SetAlpha( 255 )
|
||||
|
||||
achievements.SpawnMenuOpen()
|
||||
|
||||
if ( IsValid( self.StartupTool ) && self.StartupTool.Name ) then
|
||||
self.StartupTool:SetSelected( true )
|
||||
spawnmenu.ActivateTool( self.StartupTool.Name, true )
|
||||
self.StartupTool = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Close( bSkipAnim )
|
||||
|
||||
if ( self.m_bHangOpen ) then
|
||||
self.m_bHangOpen = false
|
||||
return
|
||||
end
|
||||
|
||||
if ( self:IsVisible() ) then RememberCursorPosition() end
|
||||
|
||||
CloseDermaMenus()
|
||||
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
self:SetMouseInputEnabled( false )
|
||||
self:SetVisible( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformLayout()
|
||||
|
||||
local MarginX = math.Clamp( ( ScrW() - 1024 ) * spawnmenu_border:GetFloat(), 25, 256 )
|
||||
local MarginY = math.Clamp( ( ScrH() - 768 ) * spawnmenu_border:GetFloat(), 25, 256 )
|
||||
|
||||
-- At this size we can't spare any space for emptiness
|
||||
if ( ScrW() < 1024 || ScrH() < 768 ) then
|
||||
MarginX = 0
|
||||
MarginY = 0
|
||||
end
|
||||
|
||||
self:DockPadding( 0, 0, 0, 0 )
|
||||
self.HorizontalDivider:DockMargin( MarginX, MarginY, MarginX, MarginY )
|
||||
self.HorizontalDivider:SetLeftMin( self.HorizontalDivider:GetWide() / 3 )
|
||||
|
||||
self.ToolToggle:AlignRight( 6 )
|
||||
self.ToolToggle:AlignTop( 6 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:StartKeyFocus( pPanel )
|
||||
|
||||
self.m_pKeyFocus = pPanel
|
||||
self:SetKeyboardInputEnabled( true )
|
||||
self:HangOpen( true )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:EndKeyFocus( pPanel )
|
||||
|
||||
if ( self.m_pKeyFocus != pPanel ) then return end
|
||||
self:SetKeyboardInputEnabled( false )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:OnSizeChanged( newW, newH )
|
||||
local divW = self.HorizontalDivider:GetWide()
|
||||
local divL = self.HorizontalDivider:GetLeftWidth()
|
||||
self:InvalidateLayout( true )
|
||||
local divWnew = self.HorizontalDivider:GetWide()
|
||||
|
||||
if ( divW > divL && divW < divWnew ) then
|
||||
local ratio = divL / divW
|
||||
self.HorizontalDivider:SetLeftWidth( ratio * divWnew )
|
||||
end
|
||||
end
|
||||
|
||||
vgui.Register( "SpawnMenu", PANEL, "EditablePanel" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Called to create the spawn menu..
|
||||
-----------------------------------------------------------]]
|
||||
local function CreateSpawnMenu()
|
||||
|
||||
if ( !hook.Run( "SpawnMenuEnabled" ) ) then return end
|
||||
|
||||
-- If we have an old spawn menu remove it.
|
||||
if ( IsValid( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:Remove()
|
||||
g_SpawnMenu = nil
|
||||
end
|
||||
|
||||
hook.Run( "PreReloadToolsMenu" )
|
||||
|
||||
-- Start Fresh
|
||||
spawnmenu.ClearToolMenus()
|
||||
|
||||
-- Add defaults for the gamemode. In sandbox these defaults
|
||||
-- are the Main/Postprocessing/Options tabs.
|
||||
-- They're added first in sandbox so they're always first
|
||||
hook.Run( "AddGamemodeToolMenuTabs" )
|
||||
|
||||
-- Use this hook to add your custom tools
|
||||
-- This ensures that the default tabs are always
|
||||
-- first.
|
||||
hook.Run( "AddToolMenuTabs" )
|
||||
|
||||
-- Use this hook to add your custom tools
|
||||
-- We add the gamemode tool menu categories first
|
||||
-- to ensure they're always at the top.
|
||||
hook.Run( "AddGamemodeToolMenuCategories" )
|
||||
hook.Run( "AddToolMenuCategories" )
|
||||
|
||||
-- Add the tabs to the tool menu before trying
|
||||
-- to populate them with tools.
|
||||
hook.Run( "PopulateToolMenu" )
|
||||
|
||||
g_SpawnMenu = vgui.Create( "SpawnMenu" )
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:SetVisible( false )
|
||||
hook.Run( "SpawnMenuCreated", g_SpawnMenu )
|
||||
end
|
||||
|
||||
CreateContextMenu()
|
||||
|
||||
hook.Run( "PostReloadToolsMenu" )
|
||||
|
||||
end
|
||||
-- Hook to create the spawnmenu at the appropriate time (when all sents and sweps are loaded)
|
||||
hook.Add( "OnGamemodeLoaded", "CreateSpawnMenu", CreateSpawnMenu )
|
||||
concommand.Add( "spawnmenu_reload", CreateSpawnMenu )
|
||||
|
||||
function GM:OnSpawnMenuOpen()
|
||||
|
||||
-- Let the gamemode decide whether we should open or not..
|
||||
if ( !hook.Call( "SpawnMenuOpen", self ) ) then return end
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:Open()
|
||||
menubar.ParentTo( g_SpawnMenu )
|
||||
end
|
||||
|
||||
hook.Call( "SpawnMenuOpened", self )
|
||||
|
||||
end
|
||||
|
||||
function GM:OnSpawnMenuClose()
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) ) then g_SpawnMenu:Close() end
|
||||
hook.Call( "SpawnMenuClosed", self )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HOOK SpawnMenuKeyboardFocusOn
|
||||
Called when text entry needs keyboard focus
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuKeyboardFocusOn( pnl )
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) && IsValid( pnl ) && pnl:HasParent( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:StartKeyFocus( pnl )
|
||||
end
|
||||
if ( IsValid( g_ContextMenu ) && IsValid( pnl ) && pnl:HasParent( g_ContextMenu ) ) then
|
||||
g_ContextMenu:StartKeyFocus( pnl )
|
||||
end
|
||||
|
||||
end
|
||||
hook.Add( "OnTextEntryGetFocus", "SpawnMenuKeyboardFocusOn", SpawnMenuKeyboardFocusOn )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HOOK SpawnMenuKeyboardFocusOff
|
||||
Called when text entry stops needing keyboard focus
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuKeyboardFocusOff( pnl )
|
||||
|
||||
if ( IsValid( g_SpawnMenu ) && IsValid( pnl ) && pnl:HasParent( g_SpawnMenu ) ) then
|
||||
g_SpawnMenu:EndKeyFocus( pnl )
|
||||
end
|
||||
|
||||
if ( IsValid( g_ContextMenu ) && IsValid( pnl ) && pnl:HasParent( g_ContextMenu ) ) then
|
||||
g_ContextMenu:EndKeyFocus( pnl )
|
||||
end
|
||||
|
||||
end
|
||||
hook.Add( "OnTextEntryLoseFocus", "SpawnMenuKeyboardFocusOff", SpawnMenuKeyboardFocusOff )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HOOK SpawnMenuOpenGUIMousePressed
|
||||
Don't do context screen clicking if spawnmenu is open
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuOpenGUIMousePressed()
|
||||
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
if ( !g_SpawnMenu:IsVisible() ) then return end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
hook.Add( "GUIMousePressed", "SpawnMenuOpenGUIMousePressed", SpawnMenuOpenGUIMousePressed )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HOOK SpawnMenuOpenGUIMousePressed
|
||||
Close spawnmenu if it's open
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuOpenGUIMouseReleased()
|
||||
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
if ( !g_SpawnMenu:IsVisible() ) then return end
|
||||
|
||||
g_SpawnMenu:Close()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "GUIMouseReleased", "SpawnMenuOpenGUIMouseReleased", SpawnMenuOpenGUIMouseReleased )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Handle spawn menu language switching
|
||||
|
||||
- The spawn menu needs to be recreated ("refreshed") after a language switch
|
||||
|
||||
- We SHOULDN'T refresh it if the user has unsaved changes to their spawn list (these would be lost!)
|
||||
- We SHOULDN'T refresh it if the user has the spawn menu open (that would be bad user experience)
|
||||
- But, we SHOULD refresh it if the user saves or reverts any changes and closes the spawn menu
|
||||
|
||||
- What if the user switches BACK to the original language they were using? Surely, a refresh is not needed now?
|
||||
- No, in this case we should still refresh the spawn menu because some text and labels do actually update during use of the spawn menu and might be left "dirty"
|
||||
-----------------------------------------------------------]]
|
||||
local function SpawnMenuLanguageChanged()
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
|
||||
if ( g_SpawnMenu.m_UnsavedModifications || g_SpawnMenu:IsVisible() ) then
|
||||
-- If there are unsaved modifications, or the spawn menu is somehow open, mark the spawn menu for recreation when the opportunity arises
|
||||
g_SpawnMenu.m_NeedsLanguageRefresh = true
|
||||
else
|
||||
-- If there are no unsaved modifications, and the spawn menu isn't open, we can go ahead and safely refresh the spawn menu
|
||||
CreateSpawnMenu()
|
||||
end
|
||||
end
|
||||
-- When gmod_language changes, call SpawnMenuLanguageChanged
|
||||
cvars.AddChangeCallback( "gmod_language", SpawnMenuLanguageChanged, "spawnmenu_reload" )
|
||||
|
||||
local function ProtectSpawnMenuChanges()
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
|
||||
-- Mark the spawn menu as having unsaved modifications
|
||||
g_SpawnMenu.m_UnsavedModifications = true
|
||||
end
|
||||
hook.Add( "SpawnlistContentChanged", "ProtectSpawnMenuChanges", ProtectSpawnMenuChanges )
|
||||
|
||||
local function SpawnMenuChangesFinished()
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
|
||||
-- Mark the spawn menu as no longer having unsaved modifications
|
||||
g_SpawnMenu.m_UnsavedModifications = nil
|
||||
end
|
||||
hook.Add( "OnRevertSpawnlist", "SpawnMenuChangesFinished", SpawnMenuChangesFinished )
|
||||
hook.Add( "OnSaveSpawnlist", "SpawnMenuChangesFinished", SpawnMenuChangesFinished )
|
||||
|
||||
local function SpawnMenuLanguageRefresh()
|
||||
if ( !IsValid( g_SpawnMenu ) ) then return end
|
||||
|
||||
-- When the spawn menu is closed, check if it needs a language refresh. If it has no unsaved modifications, refresh it!
|
||||
if ( !g_SpawnMenu.m_UnsavedModifications && g_SpawnMenu.m_NeedsLanguageRefresh ) then
|
||||
g_SpawnMenu.m_NeedsLanguageRefresh = nil
|
||||
CreateSpawnMenu()
|
||||
end
|
||||
end
|
||||
hook.Add( "OnSpawnMenuClose", "SpawnMenuLanguageRefresh", SpawnMenuLanguageRefresh )
|
||||
80
gamemodes/sandbox/gamemode/spawnmenu/toolmenu.lua
Normal file
80
gamemodes/sandbox/gamemode/spawnmenu/toolmenu.lua
Normal file
@@ -0,0 +1,80 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
include( "toolpanel.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Init()
|
||||
|
||||
self.ToolPanels = {}
|
||||
|
||||
self:LoadTools()
|
||||
|
||||
self:SetFadeTime( 0 )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
LoadTools
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:LoadTools()
|
||||
|
||||
local tools = spawnmenu.GetTools()
|
||||
|
||||
for strName, pTable in pairs( tools ) do
|
||||
|
||||
self:AddToolPanel( strName, pTable )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
AddToolPanel
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:AddToolPanel( Name, ToolTable )
|
||||
|
||||
-- I hate relying on a table's internal structure
|
||||
-- but this isn't really that avoidable.
|
||||
|
||||
local Panel = vgui.Create( "ToolPanel" )
|
||||
Panel:SetTabID( Name )
|
||||
Panel:LoadToolsFromTable( ToolTable.Items )
|
||||
Panel.PropertySheet = self
|
||||
Panel.PropertySheetTab = self:AddSheet( ToolTable.Label, Panel, ToolTable.Icon ).Tab
|
||||
|
||||
self.ToolPanels[ Name ] = Panel
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Paint
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
DPropertySheet.Paint( self, w, h )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetToolPanel
|
||||
-----------------------------------------------------------]]
|
||||
function PANEL:GetToolPanel( id )
|
||||
|
||||
return self.ToolPanels[ id ]
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ToolMenu", PANEL, "DPropertySheet" )
|
||||
268
gamemodes/sandbox/gamemode/spawnmenu/toolpanel.lua
Normal file
268
gamemodes/sandbox/gamemode/spawnmenu/toolpanel.lua
Normal file
@@ -0,0 +1,268 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
include( "controlpanel.lua" )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
AccessorFunc( PANEL, "m_TabID", "TabID" )
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self.HorizontalDivider = vgui.Create( "DHorizontalDivider", self )
|
||||
self.HorizontalDivider:Dock( FILL )
|
||||
self.HorizontalDivider:SetLeftWidth( 130 )
|
||||
self.HorizontalDivider:SetLeftMin( 130 )
|
||||
self.HorizontalDivider:SetRightMin( 200 )
|
||||
if ( ScrW() >= 1024 ) then self.HorizontalDivider:SetRightMin( 256 ) end
|
||||
self.HorizontalDivider:SetDividerWidth( 6 )
|
||||
self.HorizontalDivider:SetCookieName( "SpawnMenuToolMenuDiv" )
|
||||
|
||||
local leftContainer = vgui.Create( "Panel", self.HorizontalDivider )
|
||||
|
||||
self.SearchBar = vgui.Create( "DTextEntry", leftContainer )
|
||||
self.SearchBar:SetWidth( 130 )
|
||||
self.SearchBar:SetPlaceholderText( "#spawnmenu.quick_filter" )
|
||||
self.SearchBar:DockMargin( 0, 0, 0, 5 )
|
||||
self.SearchBar:Dock( TOP )
|
||||
self.SearchBar:SetUpdateOnType( true )
|
||||
self.SearchBar.OnValueChange = function( s, text )
|
||||
self:PerformToolFiltering( text:Trim():lower() )
|
||||
end
|
||||
|
||||
self.List = vgui.Create( "DCategoryList", leftContainer )
|
||||
self.List:SetWidth( 130 )
|
||||
self.List:Dock( FILL )
|
||||
|
||||
self.HorizontalDivider:SetLeft( leftContainer )
|
||||
|
||||
self.Content = vgui.Create( "DCategoryList", self.HorizontalDivider )
|
||||
self.HorizontalDivider:SetRight( self.Content )
|
||||
|
||||
self.LastUpdate = 0
|
||||
self.IsToolTab = false
|
||||
|
||||
local label = vgui.Create( "Panel", self )
|
||||
label:Dock( BOTTOM )
|
||||
label:SetVisible( false )
|
||||
label:SetTall( 72 )
|
||||
label.Text = ""
|
||||
label.Paint = function( s, w, h )
|
||||
local parsed = markup.Parse( "<font=DermaLarge>" .. s.Text .. "</font>", w )
|
||||
parsed:Draw( w / 2, h / 2, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 255, TEXT_ALIGN_CENTER )
|
||||
end
|
||||
self.WarningLabel = label
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Think()
|
||||
|
||||
if ( self.LastUpdate + 0.5 < SysTime() ) then
|
||||
self.LastUpdate = SysTime()
|
||||
|
||||
self:UpdateToolDisabledStatus()
|
||||
|
||||
if ( !self.IsToolTab ) then return end
|
||||
|
||||
local disabled = false
|
||||
local noToolgun = IsValid( LocalPlayer() ) && !LocalPlayer():HasWeapon( "gmod_tool" )
|
||||
if ( self.ActiveCPName ) then
|
||||
local cvar = GetConVar( "toolmode_allow_" .. self.ActiveCPName )
|
||||
if ( cvar ) then disabled = !cvar:GetBool() end
|
||||
end
|
||||
|
||||
self.WarningLabel.Text = noToolgun and "You do not have the Tool Gun to use tools!" or "Currently selected tool is disabled by the server!"
|
||||
if ( ( disabled or noToolgun ) != self.WarningLabel:IsVisible() ) then
|
||||
self.WarningLabel:SetVisible( disabled or noToolgun )
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:PerformToolFiltering( text )
|
||||
|
||||
for cid, category in ipairs( self.List.pnlCanvas:GetChildren() ) do
|
||||
local count = 0
|
||||
local category_matched = false
|
||||
|
||||
if ( string.find( category.Header:GetText():lower(), text, nil, true ) ) then
|
||||
category_matched = true
|
||||
end
|
||||
|
||||
for id, item in ipairs( category:GetChildren() ) do
|
||||
if ( item == category.Header ) then continue end
|
||||
|
||||
local str = item.Text
|
||||
if ( str:StartsWith( "#" ) ) then str = str:sub( 2 ) end
|
||||
str = language.GetPhrase( str )
|
||||
|
||||
if ( !category_matched && !string.find( str:lower(), text, nil, true ) ) then
|
||||
item:SetVisible( false )
|
||||
else
|
||||
item:SetVisible( true )
|
||||
count = count + 1
|
||||
end
|
||||
item:InvalidateLayout()
|
||||
end
|
||||
|
||||
if ( count < 1 && !category_matched ) then
|
||||
category:SetVisible( false )
|
||||
else
|
||||
category:SetVisible( true )
|
||||
|
||||
-- Make sure the category is expanded, but restore the state when we quit searching
|
||||
if ( text == "" ) then
|
||||
if ( category._preSearchState != nil ) then
|
||||
category:SetExpanded( category._preSearchState )
|
||||
category._preSearchState = nil
|
||||
end
|
||||
else
|
||||
if ( category._preSearchState == nil ) then category._preSearchState = category:GetExpanded() end
|
||||
category:SetExpanded( true )
|
||||
end
|
||||
end
|
||||
category:InvalidateLayout()
|
||||
end
|
||||
self.List.pnlCanvas:InvalidateLayout()
|
||||
self.List:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:UpdateToolDisabledStatus()
|
||||
|
||||
for cid, category in ipairs( self.List.pnlCanvas:GetChildren() ) do
|
||||
|
||||
for id, item in ipairs( category:GetChildren() ) do
|
||||
if ( item == category.Header ) then continue end
|
||||
|
||||
local cvar = GetConVar( "toolmode_allow_" .. item.Name )
|
||||
if ( !cvar ) then continue end
|
||||
|
||||
local enabled = cvar:GetBool()
|
||||
if ( enabled == item:IsEnabled() ) then continue end
|
||||
|
||||
item:SetEnabled( enabled )
|
||||
|
||||
if ( enabled ) then
|
||||
item:SetTooltip()
|
||||
else
|
||||
item:SetTooltip( "This tool is disabled by the server!" )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:LoadToolsFromTable( inTable )
|
||||
|
||||
for k, v in pairs( table.Copy( inTable ) ) do
|
||||
|
||||
if ( istable( v ) ) then
|
||||
|
||||
-- Remove these from the table so we can
|
||||
-- send the rest of the table to the other
|
||||
-- function
|
||||
|
||||
local Name = v.ItemName
|
||||
local Label = v.Text
|
||||
v.ItemName = nil
|
||||
v.Text = nil
|
||||
|
||||
if ( v[ 1 ] && v[ 1 ].Command and v[ 1 ].Command:StartsWith( "gmod_tool " ) ) then
|
||||
self.IsToolTab = true
|
||||
end
|
||||
|
||||
self:AddCategory( Name, Label, v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:AddCategory( name, catName, tItems )
|
||||
|
||||
local Category = self.List:Add( catName )
|
||||
|
||||
Category:SetCookieName( "ToolMenu." .. tostring( self:GetTabID() ) .. "." .. tostring( name ) )
|
||||
|
||||
local tools = {}
|
||||
for k, v in pairs( tItems ) do
|
||||
local name = v.Text or v.ItemName or v.Controls or v.Command or tostring( k )
|
||||
tools[ language.GetPhrase( name ) ] = v
|
||||
end
|
||||
|
||||
local currentMode = GetConVar( "gmod_toolmode" ):GetString()
|
||||
for k, v in SortedPairs( tools ) do
|
||||
|
||||
local item = Category:Add( v.Text or k )
|
||||
|
||||
item.DoClick = function( button )
|
||||
|
||||
spawnmenu.ActivateTool( button.Name )
|
||||
|
||||
end
|
||||
|
||||
item.ControlPanelBuildFunction = v.CPanelFunction
|
||||
item.Command = v.Command
|
||||
item.Name = v.ItemName
|
||||
item.Controls = v.Controls
|
||||
item.Text = v.Text
|
||||
|
||||
-- Mark this button as the one to select on first spawnmenu open
|
||||
if ( currentMode == v.ItemName ) then
|
||||
timer.Simple( 0, function() -- Have to wait a frame to get the g_SpawnMenu global, ew
|
||||
g_SpawnMenu.StartupTool = item
|
||||
end )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
-- Internal, makes the given tool highlighted in its DCategoryList
|
||||
function PANEL:SetActiveToolText( str )
|
||||
|
||||
for cid, category in ipairs( self.List.pnlCanvas:GetChildren() ) do
|
||||
|
||||
for id, item in ipairs( category:GetChildren() ) do
|
||||
if ( item == category.Header ) then continue end
|
||||
|
||||
if ( item.Name == str ) then
|
||||
self.List:UnselectAll()
|
||||
item:SetSelected( true )
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetActive( cp )
|
||||
|
||||
local kids = self.Content:GetCanvas():GetChildren()
|
||||
for k, v in pairs( kids ) do
|
||||
v:SetVisible( false )
|
||||
end
|
||||
|
||||
self.Content:AddItem( cp )
|
||||
self.ActiveCPName = cp.Name
|
||||
cp:SetVisible( true )
|
||||
cp:Dock( TOP )
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "ToolPanel", PANEL, "Panel" )
|
||||
Reference in New Issue
Block a user