mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
407 lines
12 KiB
Lua
407 lines
12 KiB
Lua
|
|
--[[
|
||
|
|
| This file was obtained through the combined efforts
|
||
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
||
|
|
|
|
||
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
||
|
|
|
|
||
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||
|
|
--]]
|
||
|
|
|
||
|
|
|
||
|
|
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 )
|