Files
wnsrc/lua/stormfox2/lib/cl_vgui.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

2150 lines
62 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 settings
local bg_color = Color(255,255,255)
local slider_col = Color(91,156,214)
local b_alpha = Color(0,0,0,60)
local c_alpha = Color(0,0,0,20)
-- Add SF Setting vgui
local function empty() end
local function wrapText(sText, wide)
wide = wide - 10
local tw,th = surface.GetTextSize(language.GetPhrase(sText))
local lines,b = 1, false
local tab = {""}
for w in string.gmatch(sText, "[^%s,]+") do
local tt = tab[#tab] .. (b and " " or "") .. w
if surface.GetTextSize(tt) >= wide then
table.insert(tab, w)
lines = lines + 1
else
tab[#tab] = tt
end
b = true
end
return tab, lines
end
local function niceName(sName)
sName = string.Replace(sName, "_", " ")
local str = ""
for s in string.gmatch(sName, "[^%s]+") do
str = str .. string.upper(s[1]) .. string.sub(s, 2) .. " "
end
return string.TrimRight(str, " ")
end
-- function to overwrite the textentity, and display the current temp setting.
local function makeTempDisplay( panel )
panel._DrawTextEntryText = panel.DrawTextEntryText
function panel:DrawTextEntryText( ... )
local s = self:GetText()
self:SetText(s .. StormFox2.Temperature.GetDisplaySymbol())
self:_DrawTextEntryText( ... )
self:SetText(s)
end
end
-- Functions to convert the temperature to the clients settings
local function valToTemp( val )
return StormFox2.Temperature.GetDisplay(val) .. StormFox2.Temperature.GetDisplaySymbol()
end
local function tempToVal( val )
return StormFox2.Temperature.Convert(StormFox2.Temperature.GetDisplayType(),"celsius",val)
end
local function PaintOver(self, w, h)
--surface.SetDrawColor(color_black)
--surface.DrawOutlinedRect(0,0,w,h)
if not self.dMark then return end
local b = self.dMark - CurTime()
if b <= 0 then
self.dMark = nil
return
end
local a = math.sin(b * math.pi * 2 )
surface.SetDrawColor(0,0,0, a * 100)
surface.DrawRect(0,0,w,h)
end
local function FindPercent( x, a, b )
return (x - a) / (b - a)
end
local function FindPercentClam( x, a, b )
return math.Clamp(FindPercent( x, a, b ), 0, 1)
end
local vgui_Create
do
local function overrideConVar( PANEL )
function PANEL:SetConVar( sName )
self._sfobj = StormFox2.Setting.GetObject( sName )
end
function PANEL:ConVarChanged( strNewValue )
if not self._sfobj then return end
self._sfobj:SetFromString( strNewValue )
end
-- Todo: Think only every 0.1 seconds?
function PANEL:ConVarStringThink()
if not self._sfobj then return end
if self.m_LV ~= nil and self._sfobj:GetValue() == self.m_LV then return end
self.m_LV = self._sfobj:GetValue()
self:SetValue( self._sfobj:GetString() )
end
function PANEL:ConVarNumberThink()
if not self._sfobj then return end
if self.m_NV ~= nil and self._sfobj:GetValue() == self.m_NV then return end
self.m_NV = self._sfobj:GetValue()
self:SetValue( tonumber(num) )
end
end
local function overrideAll( PANEL )
if not IsValid( PANEL ) then return end
if PANEL.ConVarChanged then
overrideConVar(PANEL)
end
for _, v in ipairs( PANEL:GetChildren() ) do
overrideAll( v )
end
end
function vgui_Create( str_type, self )
local PANEL = vgui.Create( str_type, self )
-- Override convar functions
overrideAll(PANEL)
return PANEL
end
end
-- Title
do
local PANEL = {}
PANEL.PaintOver = PaintOver
derma.DefineControl( "SFTitle", "", PANEL, "DLabel" )
end
-- Slider
do
local cir_size = 14
local barSize = 6
local shadowSize = 18
local sh = Material("vgui/slider")
local barSpace = 7
local PANEL = {}
AccessorFunc(PANEL, "min", "Min")
AccessorFunc(PANEL, "max", "Max")
AccessorFunc(PANEL, "value", "Value")
AccessorFunc(PANEL, "float", "Float")
-- Make sure we set a flag, if edited
function PANEL:SetMin( v )
self._set = true
self.min = v
end
function PANEL:SetMax( v )
self._set = true
self.max = v
end
function PANEL:Init()
self:SetValue( -1 )
self:SetMin(0)
self:SetMax(1)
self._set = false -- Reset flag
self:SetCursor( "hand" )
self._flagOff = false
end
function PANEL:GetValueFromPercent( p )
local range = self:GetMax() - self:GetMin()
return self:GetMin() + range * p
end
function PANEL:GetPercentFromValue( var )
return FindPercentClam( var, self:GetMin(), self:GetMax() )
end
function PANEL:GetPercentFromPoint( xPos )
local bar_width = self:GetWide() - barSpace * 2
local range = self:GetMax() - self:GetMin()
return math.Clamp((xPos - barSpace) / bar_width, 0, 1)
end
function PANEL:GetPointFromPercent( p )
local bar_width = self:GetWide() - barSpace * 2
return barSpace + bar_width * p
end
local m_cir = Material("vgui/circle")
-- Tells the slider that -1, is used to indecate it can be turned off
function PANEL:SetFlagOff( bool )
self._flagOff = bool
self:SetMin(0)
end
function PANEL:SetSetting( sName, sType, Description )
self._sfobj = StormFox2.Setting.GetObject( sName )
if not self._sfobj then return end
-- If we haven't edited the min / max, then use the convars setting. If not then make a range.
local min = self._set and self:GetMin() or self._sfobj:GetMin() or 0
local max = self._set and self:GetMax() or self._sfobj:GetMax() or self._sfobj:GetDefault() or 1
if self._flagOff then
self:SetMin(0)
else
self:SetMin(min)
end
self:SetMax(max)
local target = math.Clamp(self._sfobj:GetValue(), min, max)
self:SetValue(target)
end
function PANEL:Think()
if not self._sfobj then return end
local range = self:GetMax() - self:GetMin()
local target = self._sfobj:GetValue()
if self._flagOff and target <= 0 then
target = 0
end
local delta = math.abs(self:GetValue() - target)
self:SetValue( math.Approach(self:GetValue(), target, FrameTime() * math.max(range * 0.1, delta * 10)) )
end
function PANEL:OnMousePressed( keyCode )
if keyCode ~= MOUSE_LEFT then return end
self._down = true
self:MouseCapture( true )
end
function PANEL:OnMouseReleased( keyCode )
if keyCode == MOUSE_RIGHT then
local menu = DermaMenu(false, self)
menu:AddOption( "Reset", function()
self._sfobj:Revert()
end):SetIcon( "icon16/package.png" )
menu:Open()
return true
elseif keyCode == MOUSE_LEFT then
if not self._down then return end
self._down = false
self:MouseCapture( false )
if not self._sfobj then return end
local val = self:GetValueFromPercent(self:GetPercentFromPoint( self:CursorPos() ))
if not self:GetFloat() then
val = math.Round(val, 0)
else
val = math.Round(val, 3)
end
self._sfobj:SetValue(val)
self:SetValue(val)
end
end
function PANEL:Paint(w, h)
local bar_width = w - barSpace * 2
local bar_y = math.Round(h / 2)
local val
local min, max = self:GetMin(), self:GetMax()
if self._flagOff and self:GetValue() < 0 then
val = 0
elseif self._down then
val = self:GetValueFromPercent(self:GetPercentFromPoint( self:CursorPos() ))
if not self:GetFloat() then
self._downvalue = math.Clamp(math.Round(val), min, max)
else
self._downvalue = math.Clamp(math.Round(val,3), min, max)
end
elseif self:GetValue() < 0 and false then -- Unset
local p = ((math.sin(SysTime() * 3) + 1) / 2)
val = min + p * max
else
val = self:GetValue()
end
local percentage = FindPercentClam( val , self:GetMin() or 0, max or 1 )
if percentage < 1 then
draw.RoundedBox(30, barSpace, bar_y - barSize / 2, bar_width ,barSize, b_alpha)
end
if percentage > 0 then
draw.RoundedBox(30, barSpace, bar_y - barSize / 2, bar_width * percentage, barSize, slider_col)
end
local cir_x = self:GetPointFromPercent( percentage )
surface.SetMaterial(sh)
surface.SetDrawColor(c_alpha)
surface.DrawTexturedRectRotated(cir_x, bar_y, shadowSize, shadowSize,0)
surface.DrawTexturedRectRotated(cir_x, bar_y, shadowSize + 2, shadowSize + 2,0)
surface.SetMaterial(m_cir)
if self._down then
surface.SetDrawColor(slider_col)
else
surface.SetDrawColor(bg_color)
end
surface.DrawTexturedRectRotated(cir_x, bar_y, cir_size, cir_size,0)
end
derma.DefineControl( "SF_Slider", "", PANEL, "DPanel" )
-- DoubleSlider
local PANEL = {}
AccessorFunc(PANEL, "min", "Min")
AccessorFunc(PANEL, "max", "Max")
AccessorFunc(PANEL, "value", "MinValue")
AccessorFunc(PANEL, "value2", "MaxValue")
AccessorFunc(PANEL, "float", "Float")
function PANEL:Init()
self:SetMinValue( 0 )
self:SetMaxValue( 0 )
self:SetMin(0)
self:SetMax(1)
self:SetCursor( "hand" )
end
local m_cir = Material("vgui/circle")
function PANEL:SetSettingMin( sName, sType, Description )
self._sfobj = StormFox2.Setting.GetObject( sName )
if not self._sfobj then return end
local min = self._sfobj:GetMin() or self:GetMin() or 0
self:SetMin(min)
self:SetMax(math.max(min, self:GetMax() or 1))
end
function PANEL:SetSettingMax( sName, sType, Description )
self._sfobj2 = StormFox2.Setting.GetObject( sName )
if not self._sfobj2 then return end
local max = self._sfobj:GetMax() or self:GetMax() or 1
self:SetMax(max)
self:SetMin(max, self:GetMax() or 1)
end
function PANEL:Think()
if not self._sfobj then return end
if not self._sfobj2 then return end
local range = self:GetMax() - self:GetMin()
-- Min
local delta = math.abs(self:GetMinValue() - self._sfobj:GetValue())
self:SetMinValue( math.Approach(self:GetMinValue(), self._sfobj:GetValue(), FrameTime() * math.max(range * 0.1, delta * 10)) )
-- Max
local delta = math.abs(self:GetMaxValue() - self._sfobj2:GetValue())
self:SetMaxValue( math.Approach(self:GetMaxValue(), self._sfobj2:GetValue(), FrameTime() * math.max(range * 0.1, delta * 10)) )
end
local cir_size = 14
local barSize = 6
local shadowSize = 18
local sh = Material("vgui/slider")
local barSpace = 7
function PANEL:OnMousePressed( keyCode )
if keyCode ~= MOUSE_LEFT then return end
-- Select the closest type
local cur_p = self:GetPercentFromPoint( self:CursorPos() )
local percentage = FindPercentClam( (self:GetMinValue() + self:GetMaxValue()) / 2 , self:GetMin() or 0, self:GetMax() or 1 ) -- Center
if cur_p < percentage then
self._down = 1 -- Min
else
self._down = 2 -- Max
end
self:MouseCapture( true )
end
function PANEL:OnMouseReleased( keyCode )
if keyCode ~= MOUSE_LEFT then return end
if not self._down then return end
self:MouseCapture( false )
if not self._sfobj then return end
local val = self:GetValueFromPercent(self:GetPercentFromPoint( self:CursorPos() ))
if not self:GetFloat() then
val = math.Round(val, 0)
else
val = math.Round(val, 3)
end
if self._down == 0 then
self._sfobj:SetValue(val)
self:SetMinValue(val)
else
self._sfobj2:SetValue(val)
self:SetMaxValue(val)
end
self._down = false
end
function PANEL:Paint(w, h)
local bar_width = w - barSpace * 2
local bar_y = math.Round(h / 2)
local valMin, valMax = self:GetMinValue(), self:GetMaxValue()
if self._down then
local val = self:GetValueFromPercent(self:GetPercentFromPoint( self:CursorPos() ))
if not self:GetFloat() then
self._downvalue = math.Clamp(math.Round(val), self:GetMin(), self:GetMax())
else
self._downvalue = math.Clamp(math.Round(val,3), self:GetMin(), self:GetMax())
end
if self._down == 1 then
valMin = val
else
valMax = val
end
end
local minP = FindPercentClam( valMin , self:GetMin() or 0, self:GetMax() or 1 )
local maxP = FindPercentClam( valMax , self:GetMin() or 0, self:GetMax() or 1 )
-- BG bar
draw.RoundedBox(30, barSpace, bar_y - barSize / 2, bar_width ,barSize, b_alpha)
local cir_x = self:GetPointFromPercent( minP )
local cir_x2 = self:GetPointFromPercent( maxP )
draw.RoundedBox(30, cir_x, bar_y - barSize / 2, cir_x2 - cir_x, barSize, slider_col)
-- Min
surface.SetMaterial(sh)
surface.SetDrawColor(c_alpha)
surface.DrawTexturedRectRotated(cir_x, bar_y, shadowSize, shadowSize,0)
surface.DrawTexturedRectRotated(cir_x, bar_y, shadowSize + 2, shadowSize + 2,0)
surface.SetMaterial(m_cir)
if self._down then
surface.SetDrawColor(slider_col)
else
surface.SetDrawColor(bg_color)
end
surface.DrawTexturedRectRotated(cir_x, bar_y, cir_size, cir_size,0)
-- Max
surface.SetMaterial(sh)
surface.SetDrawColor(c_alpha)
surface.DrawTexturedRectRotated(cir_x2, bar_y, shadowSize, shadowSize,0)
surface.DrawTexturedRectRotated(cir_x2, bar_y, shadowSize + 2, shadowSize + 2,0)
surface.SetMaterial(m_cir)
if self._down then
surface.SetDrawColor(slider_col)
else
surface.SetDrawColor(bg_color)
end
surface.DrawTexturedRectRotated(cir_x2, bar_y, cir_size, cir_size,0)
end
derma.DefineControl( "SF_DoubleSlider", "", PANEL, "SF_Slider" )
end
-- Description Box
do
local lineHeight
local function getLineHeight()
if lineHeight then return lineHeight end
local ws,hs = surface.GetTextSize("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
lineHeight = hs
return hs
end
local PANEL = {}
function PANEL:Init()
self.t_text = {}
self.text = "No description"
self.font = "DermaDefault"
self.strikeout = false
end
function PANEL:SetFont( str )
self.font = str
end
function PANEL:SetStrikeOut( b )
self.strikeout = b
end
function PANEL:SetText( str )
self.text = str
surface.SetFont(self.font)
local t_text, lines = wrapText(str, self:GetWide())
self:SetTall(lines * getLineHeight())
self.t_text = t_text
end
function PANEL:PerformLayout(w, h)
surface.SetFont(self.font)
local t_text, lines = wrapText(self.text, w)
self:SetTall(lines * getLineHeight())
self.t_text = t_text
end
function PANEL:GetTextLines()
if not self.t_text then return 1 end
return math.max(1, #self.t_text)
end
function PANEL:Paint(w, h)
surface.SetDrawColor(color_white)
surface.DrawRect(0,0,w,h)
surface.SetFont(self.font)
surface.SetTextColor(color_black)
local lh = getLineHeight()
for y, str in ipairs( self.t_text ) do
local z = (y - 1) * lh
surface.SetTextPos(0, z )
surface.DrawText( str )
if self.strikeout then
surface.SetDrawColor(color_black)
local wide = #self.t_text > 1 and w or surface.GetTextSize(str)
local c = z + lh / 2 + 1
surface.DrawLine(0, c, wide, c)
end
end
end
derma.DefineControl( "SF2_TextBox", "", PANEL, "DPanel" )
end
-- Setting Tab
do
local PANEL = {}
PANEL.PaintOver = PaintOver
--PANEL.Paint = empty
function PANEL:Init()
self:DockMargin(5,0,10,0)
local label_name = vgui_Create( "DLabel", self )
label_name:SetText("Unknown Setting")
label_name:SetColor(color_black)
label_name:SetFont("DermaDefaultBold")
label_name:SizeToContents()
label_name:Dock(TOP)
self.label_name = label_name
local description = vgui_Create( "SF2_TextBox", self )
description:SetText("No description.")
description:SetPos(25, label_name:GetTall() + 2)
self.description = description
self._SetSetting = self.SetSetting
self:DockMargin(15,0,15,5)
self._cross = false
end
function PANEL:SetStrikeOut( b )
self.description:SetStrikeOut( b )
end
function PANEL:SetTitle( str )
self.label_name:SetText( language.GetPhrase(str) or str )
end
function PANEL:SetDescription( str )
self.description:SetText( language.GetPhrase(str) or str )
end
function PANEL:PerformLayout(w, h)
local maxH = 0
local x = self.description:GetPos()
self.description:SetWide(w - x)
for _, v in ipairs( self:GetChildren() ) do
local x, y = v:GetPos()
maxH = math.max(maxH, y + v:GetTall())
end
if h == maxH then return end
self:SetTall(maxH + 5)
end
function PANEL:HideTitle( bool )
if bool == false then
self.label_name:Show()
for _, v in ipairs( self:GetChildren() ) do
local x, y = v:GetPos()
v:SetPos(x, y + self.label_name:GetTall())
end
else
self.label_name:Hide()
for _, v in ipairs( self:GetChildren() ) do
local x, y = v:GetPos()
v:SetPos(x, y - self.label_name:GetTall())
end
end
self:InvalidateLayout()
return self
end
PANEL.Paint = empty
function PANEL:SetSetting( sName, sType, Description )
sType = sType or StormFox2.Setting.GetType( sName )
local obj = StormFox2.Setting.GetObject( sName )
local tName = Description and "#" .. Description or (obj and "sf_" .. obj:GetName()) or "Unknown"
self.label_name:SetText( language.GetPhrase(tName) or tName )
self.description:SetText( language.GetPhrase(tName .. ".desc") or "Unknown" )
for _, v in ipairs( self:GetChildren() ) do
if not v.SetSetting then continue end
v:SetSetting( sName, sType, Description )
end
end
function PANEL:MoveDescription( x, y )
if y then
self.description:SetPos( math.max(25, 10 + x), self.label_name:GetTall() + math.max(2, y) )
else
local x2, y2 = self.description:GetPos()
self.description:SetPos( math.max(25, 10 + x), y2 )
end
end
derma.DefineControl( "SF_Setting", "", PANEL, "DPanel" )
end
-- Boolean setting
do
local PANEL = {}
function PANEL:Init()
self.check = vgui_Create("DCheckBox", self)
self.check:SetPos(5,14)
function self.check:DoClick() -- If we're a radio-type. Never turn off.
if not self._sfobj then return end
if self:GetChecked() and self._block then return end
self._sfobj:SetValue( not self:GetChecked() )
end
function self.check:DragMousePress( keyCode )
if keyCode ~= MOUSE_RIGHT then return end
local menu = DermaMenu(false, self)
menu:AddOption( "Reset", function()
self._sfobj:Revert()
end):SetIcon( "icon16/package.png" )
menu:Open()
end
function self.check:Think()
if not self._sfobj then return end
self:SetChecked(self._sfobj:GetValue())
end
end
function PANEL:SetSetting( sName, sType, Description )
self:_SetSetting( sName, sType, Description ) -- Set title and textbox
self.check._sfobj = StormFox2.Setting.GetObject(sName)
self.check._block = self.check._sfobj:IsRadio()
end
derma.DefineControl( "SF_Setting_Bool", "", PANEL, "SF_Setting" )
end
-- String setting
do
local PANEL = {}
function PANEL:Init()
self.text = vgui_Create("DTextEntry", self)
self.text:SetPos(5,14)
self.text:SetWide(120)
self:MoveDescription(120)
end
function PANEL:SetSetting( sName, sType, Description )
self:_SetSetting( sName, sType, Description ) -- Set title and textbox
self.text:SetConVar( sName )
return self
end
derma.DefineControl( "SF_Setting_String", "", PANEL, "SF_Setting" )
end
-- Float setting
local barLength = 220 + 50
do
local PANEL = {}
function PANEL:Init()
self.text = vgui_Create("DTextEntry", self)
self.text:SetNumeric(true)
self.text:SetDrawLanguageID( false )
self.slider = vgui_Create("SF_Slider", self)
self.slider:SetPos(5,14)
self.slider:SetWide(barLength)
self.slider:SetFloat(true)
self.text:SetPos(barLength + 8,18)
self.text:SetSize(55,18)
self:MoveDescription(barLength + 60, 6)
self._isTemp = false
end
function PANEL:SetMin( v )
self.slider:SetMin( v )
return self
end
function PANEL:SetMax( v )
self.slider:SetMax( v )
return self
end
function PANEL:SetTemperature(bool)
self._isTemp = bool
return self
end
function PANEL:Think()
if not self._sfobj then return end
if self.slider._down and self.slider._downvalue then
local text
if self._isTemp then
text = self.slider._downvalue and valToTemp(self.slider._downvalue) or "?"
else
text = self.slider._downvalue
end
self.text:SetText(text)
elseif not self.text:IsEditing() then
local text
if self._flagoff and self._sfobj:GetValue() <= (self._sfobj:GetMin() or -1) then
text = ""
elseif self._isTemp then
text = valToTemp(self._sfobj:GetValue())
else
text = self._sfobj:GetValue()
end
self.text:SetText(text)
end
end
function PANEL:SetSetting( sName, sType, Description )
local _sfobj = StormFox2.Setting.GetObject( sName )
self._sfobj = _sfobj
self:_SetSetting( sName, sType, Description ) -- Set title and textbox
--self.text:SetConVar( sName )
function self.text:OnEnter( val )
val = string.match(val, "[%d%.-]+") or val
if _sfobj:GetMin() then
val = math.max(_sfobj:GetMin(), val)
end
if _sfobj:GetMax() then
val = math.min(_sfobj:GetMax(), val)
end
_sfobj:SetValue(val)
self:SetText(tostring(val))
end
return self
end
derma.DefineControl( "SF_Setting_Float", "", PANEL, "SF_Setting" )
end
-- Int setting
do
local PANEL = {}
function PANEL:Init()
self.text = vgui_Create("DTextEntry", self)
self.text:SetNumeric(true)
self.text:SetDrawLanguageID( false )
self.slider = vgui_Create("SF_Slider", self)
self.slider:SetPos(5,14)
self.slider:SetWide(barLength)
self.text:SetPos(barLength + 8,18)
self.text:SetSize(55,18)
self:MoveDescription(barLength + 60, 6)
self._isTemp = false
end
function PANEL:SetMin( v )
self.slider:SetMin( v )
return self
end
function PANEL:SetMax( v )
self.slider:SetMax( v )
return self
end
function PANEL:SetTemperature(bool)
self._isTemp = bool
return self
end
function PANEL:Think()
if not self._sfobj then return end
if self.slider._down and self.slider._downvalue then
local text
if self._isTemp then
text = self.slider._downvalue and valToTemp(self.slider._downvalue) or "?"
else
text = self.slider._downvalue
end
self.text:SetText(text)
elseif not self.text:IsEditing() then
local text
if self._isTemp then
text = valToTemp(self._sfobj:GetValue())
else
text = self._sfobj:GetValue()
end
self.text:SetText(text)
end
end
function PANEL:SetSetting( sName, sType, Description )
local _sfobj = StormFox2.Setting.GetObject( sName )
self._sfobj = _sfobj
self:_SetSetting( sName, sType, Description ) -- Set title and textbox
--self.text:SetConVar( sName )
function self.text:OnEnter( val )
val = string.match(val, "[%d%.-]+") or val
local clamp = tonumber( val ) or 0
if _sfobj:GetMax() then
clamp = math.min(clamp, _sfobj:GetMax())
end
if _sfobj:GetMin() then
clamp = math.max(clamp, _sfobj:GetMin())
end
_sfobj:SetValue(clamp)
self:SetText(tostring(clamp))
end
return self
end
derma.DefineControl( "SF_Setting_Int", "", PANEL, "SF_Setting" )
end
-- Table / Enums
do
local sortNum = function(a,b)
if type(a) == "boolean" then
return a or b
end
return a>b
end
local sortStr = function(a,b) return a<b end
local PANEL = {}
function PANEL:Init()
self.cbox = vgui_Create("DComboBox", self)
self.cbox:SetPos(5,14)
self.cbox:SetSize(80,20)
self:MoveDescription(80)
end
function PANEL:SetSetting( sName, sType, Description )
sType = sType or StormFox2.Setting.GetType( sName )
local tab, sortorder = sType[1], sType[2]
self._options = tab
self:_SetSetting( sName, sType, Description ) -- Set title and textbox
self.cbox:SetConVar( sName )
local options = table.GetKeys( tab )
local _sfobj = StormFox2.Setting.GetObject( sName )
self._sfobj = _sfobj
local s_type = type(_sfobj:GetValue())
local sort_func = (s_type == "number" or s_type == "boolean") and sortNum or sortStr
-- Change width to match the options
do
surface.SetFont("DermaDefault")
local width = 80 -- Min size
for k,v in pairs(options) do
local text = niceName( language.GetPhrase(tab[v]) )
local tw = surface.GetTextSize(text) + 24
width = math.max(width, tw)
end
self.cbox:SetWide(width)
self:MoveDescription(width)
end
if not sortorder then -- We don't have an order
table.sort(options, sort_func)
for k,v in ipairs(options) do
local text = niceName( language.GetPhrase(tab[v]))
self.cbox:AddChoice( text, v, _sfobj:GetValue() == v )
end
else
for _,v in ipairs(sortorder) do
local text = niceName( language.GetPhrase(tab[v] or "UNKNOWN"))
self.cbox:AddChoice( text, v, _sfobj:GetValue() == v )
end
if #sortorder ~= #tab then -- Add the rest
table.sort(options, sort_func)
for _,v in ipairs(options) do
if table.HasValue(sortorder, v) then continue end
local text = niceName( language.GetPhrase(tab[v]))
self.cbox:AddChoice( text, v, _sfobj:GetValue() == v )
end
end
end
function self.cbox:OnSelect( index, text, data )
if not data then data = false end -- Somehow, false doesn't get returned
_sfobj:SetValue(data)
end
return self
end
function PANEL:Think()
if not self._sfobj or not self._options then return end
self.cbox:SetText(self._options[self._sfobj:GetValue()] or "?")
end
derma.DefineControl( "SF_Setting_Enum", "", PANEL, "SF_Setting" )
end
-- Float-Special (CheckBox makes it lowest or -1)
do
local PANEL = {}
local OldPanel = vgui.GetControlTable("SF_Setting_Float")
local mat = Material("icon16/cross.png")
function PANEL:Init()
self.check = vgui_Create("DCheckBox", self)
self.check:SetPos(5,18)
self.slider:SetPos(5 + 18,14)
self.text:SetPos(barLength + 8,18)
self.slider:SetWide(barLength - 18)
self.slider:SetFlagOff( true ) -- Tells the slider that anything below -1, is disabled
self._flagoff = true
function self.text:PaintOver(w,h)
if #self:GetText() > 0 or self:IsHovered() then return end
surface.SetMaterial(mat)
surface.SetDrawColor(color_white)
surface.DrawTexturedRect(w / 2 - 8, h / 2 - 8, 16, 16)
end
function self.check:DoClick() -- If we're a radio-type. Never turn off.
if self:GetChecked() and self._block then return end
self:Toggle()
end
self:MoveDescription(barLength + 60, 6)
end
function PANEL:SetMin( v )
self.slider:SetMin( v )
return self
end
function PANEL:SetMax( v )
self.slider:SetMax( v )
return self
end
function PANEL:Think()
if not self._sfobj then return end
OldPanel["Think"](self)
local min = self._sfobj:GetMin() or -1
self.check:SetChecked(self._sfobj:GetValue() > min)
end
function PANEL:SetDefaultEnable( var )
self.defaultEnable = var
end
function PANEL:SetSetting( sName, sType, Description )
self:_SetSetting( sName, sType, Description ) -- Set title and textbox
local _sfobj = StormFox2.Setting.GetObject( sName )
self._sfobj = _sfobj
--self.text:SetConVar( sName )
self.check._block = _sfobj:IsRadio()
function self.text:OnEnter( val )
val = tonumber( string.match(val, "[%d%.-]+") or val ) or 0
if _sfobj:GetMin() then
val = math.max(_sfobj:GetMin(), val)
end
if _sfobj:GetMax() then
val = math.min(_sfobj:GetMax(), val)
end
_sfobj:SetValue(val)
self:SetText(tostring(val))
end
local mainPanel = self
function self.check:DoClick()
local min = _sfobj:GetMin() or -1
local b = _sfobj:GetValue() > 0
if b then
_sfobj:SetValue(min)
else
local n = math.max(mainPanel.defaultEnable or _sfobj:GetDefault(), 1)
_sfobj:SetValue(n)
end
end
return self
end
derma.DefineControl( "SF_Setting_FloatSpecial", "", PANEL, "SF_Setting_Float" )
end
-- Time Object
local PANEL = {}
local function OnMousePressed( self, mcode )
if ( mcode == MOUSE_LEFT ) then
self:OnGetFocus()
else
local menu = DermaMenu(false, self.base)
local obj = StormFox2.Setting.GetObject("12h_display")
local text = (obj:GetValue() and "24-" or "12-") .. language.GetPhrase("clock")
menu:AddOption( text, function()
obj:SetValue( not obj:GetValue())
end):SetIcon( "icon16/clock.png" )
return true
end
end
local function NewPaint(self, w, h, off)
surface.SetFont("SF2_TimeSet")
local tex = (self:GetValue() or "")
local tw,th = surface.GetTextSize(tex)
surface.SetTextColor(self.color or color_black)
surface.SetTextPos(w / 2 - tw / 2,h / 2 - th / 2)
if self:HasFocus() then
local e = (math.Round(SysTime() % 1) == 1 and "_" or "")
surface.DrawText( tex .. e )
else
surface.DrawText( tex )
end
end
function PANEL:BGThink()
if self.lastDisplay ~= cDis then
self:InvalidateLayout()
self.lastDisplay = cDis
end
local _12 = StormFox2.Setting.Get("12h_display")
if not self.hour:IsEditing() and not self.hour._SETONLOST then
local h = StormFox2.Time.GetHours( self.value, _12 )
if h < 10 then h = "0" .. h end
self.hour:SetText(h)
end
if not self.min:IsEditing() then
local m = StormFox2.Time.GetMinutes( self.value )
if m < 10 then m = "0" .. m end
self.min:SetText(m)
end
if _12 then
self.ampm:SetText( StormFox2.Time.GetAMPM() )
end
end
function PANEL:Init()
self.bg = vgui_Create("DPanel",self)
function self.bg:IsSelected() return false end
function self.bg:GetToggle() return false end
local hour = vgui.Create("DTextEntry", self.bg)
self.hour = hour
local min = vgui.Create("DTextEntry", self.bg)
self.min = min
self.ampm = vgui.Create("DButton", self)
function self.bg:Paint( w, h )
local cDis = StormFox2.Setting.Get("12h_display")
self.Hovered = hour.Hovered or min.Hovered
self.Depressed= hour:IsEditing() or min:IsEditing()
derma.SkinHook( "Paint", "Button", self, w, h )
surface.SetFont("SF2_TimeSet")
local tw,th = surface.GetTextSize(":")
surface.SetTextColor(self.color or color_black)
surface.SetTextPos(w / 2 - tw / 2,h / 2 - th / 2 - 2)
surface.DrawText(":")
end
function self.bg:IsHovered()
return hour:IsHovered() or min:IsHovered()
end
function self.bg:IsDown()
return hour:IsEditing() or min:IsEditing()
end
function self.hour.OnGetFocus(self)
local tex = self._SETONFOC or ""
self:SetValue(tex)
self:SetCaretPos(#tex)
self._SETONFOC = nil
end
self.min.OnGetFocus = self.hour.OnGetFocus
function self.min:OnLoseFocus()
if hour._SETONLOST then -- hour got unset variables
self.base:_SetNewVar( )
hour._SETONLOST = nil
end
end
self.bg:SetPos( 2,0 )
self.hour:SetPos(0,0)
self.hour:SetWide(30)
self.hour:SetTall(30)
self.hour.Paint = NewPaint
self.hour.OnMousePressed = OnMousePressed
self.hour.base = self
self.min:SetPos(32,0)
self.min:SetWide(30)
self.min:SetTall(30)
self.min.Paint = NewPaint
self.min.OnMousePressed = OnMousePressed
self.min.base = self
self.ampm:SetPos(66 + 2,0)
self.ampm:SetWide(34)
self.ampm:SetTall(30)
self.ampm:SetFont("SF2_TimeSetAM")
self.ampm.base = self
if not StormFox2.Setting.Get("12h_display") then
self.ampm:Hide()
self.lastDisplay = false
else
self.lastDisplay = true
self.ampm:SetText("AM")
end
self.hour:SetDrawLanguageID( false )
self.min:SetDrawLanguageID( false )
self.hour:SetNumeric(true)
self.min:SetNumeric(true)
self:SetValue( 0 )
self:SetTall( 30 )
-- Logic
function self.hour:OnChange( str )
if #self:GetValue() <= 2 then return end
self._SETONLOST = self:GetValue():sub(0,2)
min._SETONFOC = self:GetValue():sub(3)
self:KillFocus()
min:RequestFocus()
self:SetText(self._SETONLOST )
end
function self.hour:OnEnter()
self.base:_SetNewVar()
end
self.min.OnEnter = self.hour.OnEnter
function self.ampm:DoClick()
self:SetText( self:GetText() == "AM" and "PM" or "AM")
self.base:_SetNewVar()
end
end
function PANEL:SetValue( num )
self.value = num
end
function PANEL:GetValue()
return self.value
end
function PANEL:_SetNewVar()
local str = self.hour:GetText() .. ":" .. self.min:GetText()
if StormFox2.Setting.Get("12h_display") then
str = str .. " " .. self.ampm:GetText()
end
self.value = StormFox2.Time.StringToTime( str )
self:OnNewValue( self.value )
end
PANEL.OnNewValue = function() end
PANEL.Paint = PANEL.BGThink
function PANEL:PerformLayout(pw, ph)
local w = (pw - 8) / 2
if StormFox2.Setting.Get("12h_display") then
w = (pw - 8) / 3
self.ampm:Show( )
else
self.ampm:Hide( true )
end
self.hour:SetWide(w)
self.min:SetWide(w)
self.ampm:SetWide(w)
self.bg:SetWide(w * 2)
self.bg:SetHeight( ph )
--self.hour:SetPos(0,0)
self.min:SetPos(w, 0)
self.ampm:SetPos(w * 2 + 6, 0)
self.hour:SetHeight( ph )
self.min:SetHeight( ph )
self.ampm:SetHeight( ph )
end
derma.DefineControl( "SF_TIME", "", PANEL, "DPanel" )
-- Time
do
local PANEL = {}
surface.CreateFont("SF2_TimeSet", {
font = "Arial", -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name
extended = false,
size = 26,
weight = 50,
blursize = 0,
scanlines = 0,
antialias = true,
underline = false,
italic = false,
strikeout = false,
symbol = false,
rotary = false,
shadow = false,
additive = false,
outline = false,
} )
surface.CreateFont("SF2_TimeSetAM", {
font = "Arial", -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name
extended = false,
size = 22,
weight = 50,
blursize = 0,
scanlines = 0,
antialias = true,
underline = false,
italic = false,
strikeout = false,
symbol = false,
rotary = false,
shadow = false,
additive = false,
outline = false,
} )
local function NewPaint(self, w, h, off)
surface.SetFont("SF2_TimeSet")
local tw,th = surface.GetTextSize("ABCDEFGHIJ")
surface.SetTextColor(color_black)
surface.SetTextPos(2,h / 2 - th / 2)
local tex = (self:GetValue() or "")
local e = (math.Round(SysTime() % 1) == 1 and "_" or "")
if self:HasFocus() and #tex < 2 then
surface.DrawText( tex .. e )
else
surface.DrawText( tex )
end
if self:HasFocus() and #tex == 2 then
local tw = surface.GetTextSize(tex:sub(0,1))
surface.SetTextPos(2 + tw,h / 2 - th / 2)
surface.DrawText( e )
end
end
local function OnMousePressed( self, mcode )
if ( mcode == MOUSE_LEFT ) then
self:OnGetFocus()
else
local menu = DermaMenu(false, self)
local obj = StormFox2.Setting.GetObject("12h_display")
local text = (obj:GetValue() and "24-" or "12-") .. language.GetPhrase("clock")
menu:AddOption( text, function()
obj:SetValue( not obj:GetValue())
end):SetIcon( "icon16/clock.png" )
menu:AddOption( "Reset", function()
self._sfobj:Revert()
end):SetIcon( "icon16/package.png" )
menu:Open()
return true
end
end
function PANEL:Init()
local b = vgui_Create("DPanel", self) -- All options
b.Paint = empty
local bg = vgui_Create("DPanel", b) -- Background
self.hour = vgui.Create("DTextEntry", b)
self.min = vgui.Create("DTextEntry", b)
self.ampm = vgui.Create("DButton", b)
self.bg = bg
self.b = b
self.bar_ex = 0
b:SetPos(6,14)
b:SetSize(66 + 34 + 2, 30)
bg:SetSize(66, 30)
function bg:IsSelected() return false end
function bg:GetToggle() return false end
function bg:IsDown()
return hour:IsEditing() or min:IsEditing()
end
local hour, min = self.hour, self.min
do
function bg:Paint( w, h )
self.Hovered = hour.Hovered or min.Hovered
self.Depressed= hour:IsEditing() or min:IsEditing()
derma.SkinHook( "Paint", "Button", self, w, h )
surface.SetFont("SF2_TimeSet")
local tw,th = surface.GetTextSize(":")
surface.SetTextColor(color_black)
surface.SetTextPos(w / 2 - tw / 2,h / 2 - th / 2 - 2)
surface.DrawText(":")
end
end
self.hour:SetPos(2,0)
self.hour:SetWide(30)
self.hour:SetTall(30)
self.min:SetPos(34,0)
self.min:SetWide(30)
self.min:SetTall(30)
self.ampm:SetPos(66 + 2,0)
self.ampm:SetWide(34)
self.ampm:SetTall(30)
self.ampm:SetFont("SF2_TimeSetAM")
function self.ampm:UpdateColours( skin )
if ( !self:IsEnabled() ) then return self:SetTextStyleColor( skin.Colours.Button.Disabled ) end
if ( self:IsDown() || self.m_bSelected ) then return self:SetTextStyleColor( skin.Colours.Button.Down ) end
if ( self.Hovered ) then return self:SetTextStyleColor( skin.Colours.Button.Hover ) end
return self:SetTextStyleColor( color_black )
end
self.hour:SetNumeric(true)
self.hour:SetDrawLanguageID( false )
self.hour.Paint = NewPaint
self.hour:SetText("00")
local panel = self
function self.hour.OnGetFocus(self)
self:SetValue("")
end
function self.hour:OnEnter()
local num = tonumber( self:GetValue() or "" ) or 0
local lim = StormFox2.Setting.Get("12h_display") and 12 or 24
num = math.Clamp(num, 0, lim)
if num < 10 then
self:SetText("0" .. num)
else
self:SetText(num)
end
panel:OnNewValue()
end
function self.hour:OnChange()
if string.find(self:GetValue(), "-") then
self:SetText(string.Replace(self:GetValue(), "-", ""))
end
if #self:GetValue() >= 3 then -- Can't enter more numbers
self:FocusPrevious()
self:OnEnter()
elseif #self:GetValue() == 2 then
--self:OnEnter()
self:KillFocus()
min:RequestFocus()
min._setonlosefocus = true
end
end
function self.hour.OnLoseFocus( self )
if #self:GetText() < 2 then return end
-- We lost focus and the player has entered two numbers in. Should be set. Not everyone hits enter
self:OnEnter()
end
self.min:SetNumeric(true)
self.min:SetDrawLanguageID( false )
self.min.Paint = NewPaint
self.min:SetText("00")
function self.min.OnGetFocus(self)
self._oldVar = self:GetValue()
self:SetValue("")
end
function self.min:OnEnter()
-- Hour value has changed, and this is empty. We then use the last value instead.
if #self:GetText() < 1 and self._setonlosefocus and self._oldVar then
self:SetValue( self._oldVar )
end
self._setonlosefocus = nil
local num = tonumber( self:GetValue() or "" ) or 0
num = math.Clamp(num, 0, 59)
if num < 10 then
self:SetText("0" .. num)
else
self:SetText(num)
end
panel:OnNewValue( num )
end
function self.min:OnChange()
if string.find(self:GetValue(), "-") then
self:SetText(string.Replace(self:GetValue(), "-", ""))
end
if #self:GetValue() >= 2 then -- Can't enter more numbers
self:FocusPrevious()
self:OnEnter()
end
end
function self.min.OnLoseFocus( self )
-- We lost focus and the player has entered two numbers in. Should be set
if #self:GetText() < 2 and not (self._oldVar and self._setonlosefocus) then return end
-- We have a set-on-leave flag
if self._setonlosefocus and self._oldVar then
self:SetValue(self._oldVar)
end
self._setonlosefocus = nil
self:OnEnter()
end
function self.ampm:DoClick()
if self:GetText() == "AM" then
self:SetText("PM")
else
self:SetText("AM")
end
panel:OnNewValue()
end
hour.OnMousePressed = OnMousePressed
min.OnMousePressed = OnMousePressed
self:MoveDescription(105 + self.bar_ex,4)
end
function PANEL:OnNewValue()
local str = tonumber(self.hour:GetText()) .. ":" .. tonumber(self.min:GetText())
if StormFox2.Setting.Get("12h_display") then
str = str .. self.ampm:GetText()
end
self._sfobj:SetValue( StormFox2.Time.StringToTime(str) )
end
function PANEL:Think()
var = var or 0
if not self._sfobj then return end
local _12 = StormFox2.Setting.Get("12h_display")
local var = self._sfobj:GetValue()
if var < 0 then
self.b:SetDisabled( true )
self.hour:SetText("00")
self.min:SetText("00")
self.ampm:SetText("AM")
if _12 then
self.ampm:SetText(StormFox2.Time.GetAMPM( self._sfobj:GetValue() ))
if not self.ampm:IsVisible() then
self.ampm:Show()
self:MoveDescription(105 + self.bar_ex,4)
end
else
if self.ampm:IsVisible() then
self.ampm:Hide()
self:MoveDescription(70 + self.bar_ex,4)
end
end
else
self.b:SetDisabled( false )
if not self.hour:IsEditing() then
local h = StormFox2.Time.GetHours( self._sfobj:GetValue(), _12 )
if h < 10 then
h = "0" .. h
end
self.hour:SetText(h)
end
if not self.min:IsEditing() then
local h = StormFox2.Time.GetMinutes( self._sfobj:GetValue(), _12 )
if h < 10 then
h = "0" .. h
end
self.min:SetText(h)
end
if _12 then
self.ampm:SetText(StormFox2.Time.GetAMPM( self._sfobj:GetValue() ))
if not self.ampm:IsVisible() then
self.ampm:Show()
self:MoveDescription(105 + self.bar_ex,4)
end
else
if self.ampm:IsVisible() then
self.ampm:Hide()
self:MoveDescription(70 + self.bar_ex,4)
end
end
end
end
function PANEL:SetSetting( sName, sType, Description )
self:_SetSetting( sName, sType, Description ) -- Set title and textbox
self._sfobj = StormFox2.Setting.GetObject( sName )
self.min._sfobj = self._sfobj
self.hour._sfobj = self._sfobj
--self.check:SetConVar( sName )
return self
end
derma.DefineControl( "SF_Setting_Time", "", PANEL, "SF_Setting" )
end
-- Time Toggle
do
local OldPanel = vgui.GetControlTable("SF_Setting_Time")
local PANEL = {}
function PANEL:Init()
self.check = vgui_Create("DCheckBox", self)
self.check:SetPos(5,20)
self.b:SetPos(24,14)
self:MoveDescription(105 + 18,4)
self.bar_ex = 18
end
function PANEL:Think()
OldPanel.Think(self)
if not self._sfobj then return end
local b = self._sfobj:GetValue() >= 0
self.check:SetChecked(b)
end
function PANEL:SetSetting( sName, sType, Description )
OldPanel.SetSetting( self, sName, sType, Description )
local _sfobj = StormFox2.Setting.GetObject( sName )
self.check._block = _sfobj:IsRadio()
function self.check:DoClick()
if self:GetChecked() and self._block then return end
local b = _sfobj:GetValue() > 0
if b then
_sfobj:SetValue(-1)
else
local default = _sfobj:GetDefault()
if default < 0 then default = 720 end
_sfobj:SetValue(default)
end
end
return self
end
derma.DefineControl( "SF_Setting_TimeToggle", "", PANEL, "SF_Setting_Time" )
end
-- DoubleInt setting
do
local PANEL = {}
function PANEL:Init()
self.text = vgui_Create("DTextEntry", self)
self.text:SetNumeric(true)
self.text:SetDrawLanguageID( false )
self.slider = vgui_Create("SF_DoubleSlider", self)
self.slider:SetPos(5,14)
self.slider:SetWide(barLength)
self.text:SetPos(barLength + 8,18)
self.text:SetSize(55,18)
self:MoveDescription(barLength + 60, 6)
self._isTemp = false
end
function PANEL:SetTemperature(bool)
self._isTemp = bool
end
function PANEL:Think()
if not self._sfobj then return end
if self.slider._down and self.slider._downvalue then
local text
if self._isTemp then
text = self.slider._downvalue and valToTemp(self.slider._downvalue) or "?"
else
text = self.slider._downvalue
end
self.text:SetText(text)
elseif not self.text:IsEditing() then
local text
if self._isTemp then
text = valToTemp(self._sfobj:GetValue())
else
text = self._sfobj:GetValue()
end
self.text:SetText(text)
end
end
function PANEL:SetSettingMin( sName, sType, Description )
local _sfobj = StormFox2.Setting.GetObject( sName )
self._sfobj = _sfobj
self:_SetSetting( sName, sType, Description ) -- Set title and textbox
self.slider:SetSettingMin( sName, sType, Description )
--self.text:SetConVar( sName )
function self.text:OnEnter( val )
val = string.match(val, "[%d%.]+") or val
local clamp = math.Clamp(tonumber( val ), _sfobj:GetMin(), _sfobj:GetMax())
_sfobj:SetValue(clamp)
self:SetText(tostring(clamp))
end
end
function PANEL:SetSettingMax( sName, sType, Description )
local _sfobj2 = StormFox2.Setting.GetObject( sName )
self._sfobj2 = _sfobj
self:_SetSetting( sName, sType, Description ) -- Set title and textbox
self.slider:SetSettingMax( sName, sType, Description )
--self.text:SetConVar( sName )
end
function PANEL:SetMin( var )
self.slider:SetMin( var )
end
function PANEL:SetMax( var )
self.slider:SetMax( var )
end
derma.DefineControl( "SF_Setting_Double", "", PANEL, "SF_Setting" )
end
-- Hud Ring
do
local PANEL = {}
local m_ring = Material("stormfox2/hud/hudring.png")
local cCol1 = Color(55,55,55,55)
local cCol2 = Color(55,55,255,105)
local seg = 40
function PANEL:SetColor(r,g,b,a)
self.cCol2 = (r and g and b) and Color(r,g,b,a or 105) or r
return self
end
function PANEL:Init()
self._val = 1
self._off = 0.05
self.cCol1 = cCol1
self.cCol2 = cCol2
end
function PANEL:SetValue(nNum)
self._val = math.Clamp(nNum, 0, 1)
self:RebuildPoly()
return self
end
function PANEL:SetText(sText)
self._text = sText
return self
end
function PANEL:RebuildPoly()
local pw, ph = self:GetWide(), self:GetTall()
local x,y = pw / 2, ph / 2
local polyMul = 1.2
local radius = math.min(pw, ph) / 2 * polyMul
local mul2 = 2 / polyMul
-- Generate poly
self._poly = {}
local seg = 40
table.insert( self._poly, { x = x, y = y, u = 0.5, v = 0.5 } )
local n = self._val * seg
for i = 0, n do
local a = math.rad( ( i / seg ) * -360 )
table.insert( self._poly, { x = x + math.sin( a ) * radius, y = y + math.cos( a ) * radius, u = math.sin( a ) / mul2 + 0.5, v = math.cos( a ) / mul2 + 0.5 } )
end
local a = math.rad( ( n / seg ) * -360 )
table.insert( self._poly, { x = x + math.sin( a ) * radius, y = y + math.cos( a ) * radius, u = math.sin( a ) / mul2 + 0.5, v = math.cos( a ) / mul2 + 0.5 } )
table.insert( self._poly, { x = x, y = y, u = 0.5, v = 0.5 } )
end
function PANEL:PerformLayout(pw, ph)
self:RebuildPoly()
end
function PANEL:Paint(w,h)
if self._text then
local td = string.Explode("\n",self._text)
for k,v in ipairs(td) do
local n = k - 1
draw.SimpleText(v, "DermaDefault", w / 2, h / 2 + n * 12 - (#td - 1) * 6, color_black, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
else
draw.SimpleText(self._val, "DermaDefault", w / 2, h / 2, color_black, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
if not self._poly then return end
surface.SetMaterial(m_ring)
surface.SetDrawColor(self.cCol1)
surface.DrawTexturedRect(self._x or 0,self._y or 0,self._w or w,self._h or h)
surface.SetDrawColor(self.cCol2)
surface.DrawPoly(self._poly)
end
derma.DefineControl( "SF_Setting_Ring", "", PANEL, "DPanel" )
end
-- Old
-- Ring
do
local PANEL = {}
derma.DefineControl( "SF_HudRing", "", PANEL, "DPanel" )
end
-- World Display
do
local PANEL = {}
local owm = Material("stormfox2/hud/openweather.png")
local PANEL = {}
AccessorFunc( PANEL, "m_lat", "Lat" )
AccessorFunc( PANEL, "m_lon", "Lon" )
AccessorFunc( PANEL, "m_zoom","Zoom" )
local w_map = Material("stormfox2/hud/world.png")
local c = Color(0,0,0,55)
function PANEL:GetUV( lat, lon )
lat = math.Clamp(lat / 90, -1, 1) * 0.5
lon = math.Clamp(lon / 180, -1, 1) * 0.5
return 0.5 + lon, 0.5 - lat
end
function PANEL:Init()
self._map = vgui.Create("DPanel", self)
self:SetLat(StormFox2.Setting.Get("openweathermap_lat", 52.6139095))
self:SetLon(StormFox2.Setting.Get("openweathermap_lon", -2.0059601))
self:SetSize(400, 300)
self:SetZoom(0)
self._range = 1
self._map._s = self
function self._map:GetUV( lat, lon )
return self._s:GetUV( lat, lon )
end
function self._map:Paint(w,h)
if self._s:GetDisabled() then return end
surface.SetDrawColor(color_white)
surface.SetMaterial( w_map )
surface.DrawTexturedRect(0,0,w,h)
local u, v = self:GetUV( self._s:GetLat(), self._s:GetLon())
local ws = math.ceil(w / 360)
local hs = math.ceil(h / 180)
surface.SetDrawColor(color_black)
local xx,yy = u * w - ws / 2, v * h - hs / 2
surface.DrawOutlinedRect(xx,yy, ws, hs)
surface.SetDrawColor(c)
c.a = 150 + math.sin(SysTime() * 10) * 50
local xT = math.max(1, ws / 4)
local yT = math.max(1, hs / 4)
-- X
surface.DrawRect(0, yy + hs * .5 - xT / 2, xx, yT)
surface.DrawRect(xx + ws, yy + hs * .5 - xT / 2, w - xx - ws, yT)
--Y
surface.DrawRect(xx + ws * 0.5 - yT / 2, 0, xT, yy)
surface.DrawRect(xx + ws * 0.5 - yT / 2, yy + hs, xT, h - yy - hs)
end
self:SetMouseInputEnabled( true )
StormFox2.Setting.Callback("openweathermap_lat",function(vVar,_,_, self)
self:SetLat( tonumber(vVar) )
self:ReSize()
end,self)
StormFox2.Setting.Callback("openweathermap_lon",function(vVar,_,_, self)
self:SetLon( tonumber(vVar) )
self:ReSize()
end,self)
end
function PANEL:ReSize()
local z = self:GetZoom() * 0.5
local w,h = 1617 * z, 808 * z
if w < self:GetWide() or h < self:GetTall() then
z = math.max(self:GetWide() / 1617, self:GetTall() / 808)
w = 1617 * z
h = 808 * z
end
self._map:SetSize(w, h)
local u, v = self:GetUV( self:GetLat(), self:GetLon())
local px,py = -w * u + self:GetWide() / 2, -h * v + self:GetTall() / 2
px = math.Clamp(px, -w, 0)
py = math.Clamp(py, -h, 0)
self._map:SetPos(px,py)
end
function PANEL:OnMouseWheeled( sD )
local z = self:GetZoom() + sD / 2
self:SetZoom( math.Clamp(z, 1, 28) )
self:ReSize()
return true
end
function PANEL:PerformLayout()
self:ReSize()
end
local c = Color( 254, 254, 234 )
function PANEL:Paint(w,h)
if self:GetDisabled() then return end
surface.SetDrawColor(c)
surface.DrawRect(0,0,w,h)
local x, y = self._map:GetPos()
local ws, hs = self._map:GetSize()
surface.SetDrawColor(color_white)
surface.SetMaterial( w_map )
if x < 0 then
surface.DrawTexturedRect(x + ws,y,ws,hs)
else
surface.DrawTexturedRect(x - ws,y,ws,hs)
end
end
function PANEL:PaintOver(w,h)
surface.SetDrawColor(color_black)
surface.SetMaterial(owm)
local tw = w / 5
local th = tw * 0.42
surface.DrawTexturedRect(0, h - th, tw, th)
end
derma.DefineControl( "SF_WorldMap", "", PANEL, "DPanel" )
end
-- Day Display
do
local PANEL = {}
derma.DefineControl( "SF_WeatherHour", "", PANEL, "DPanel" )
end
-- Weather Display
do
local PANEL = {}
derma.DefineControl( "SF_WeatherMap", "", PANEL, "DPanel" )
end
-- Menu
do
local function empty() end
local function switch(sName, tab, buttons, sCookie)
sName = string.lower(sName)
local pnl
for k, v in pairs(tab) do
if k == sName then
v:Show()
pnl = v
else
v:Hide()
end
end
if not IsValid(pnl) or pnl:GetDisabled() then
pnl = tab["start"]
sName = "start"
if IsValid(pnl) then
pnl:Show()
end
end
for k,v in pairs(buttons) do
v._selected = k == sName
end
if sCookie then
cookie.Set(sCookie, sName)
end
return pnl
end
local function addSetting(sName, pPanel, _type, _desc)
local setting
if type(_type) == "table" then
setting = vgui_Create("SF_Setting_Enum", pPanel)
elseif _type == "boolean" or _type == "bool" then
setting = vgui_Create("SF_Setting_Bool", pPanel)
elseif _type == "float" then
setting = vgui_Create("SF_Setting_Float", pPanel)
elseif _type == "special_float" then
setting = vgui_Create("SF_Setting_FloatSpecial", pPanel)
elseif _type == "number" then
setting = vgui_Create("SF_Setting_Int", pPanel)
elseif _type == "time" then
setting = vgui_Create("SF_Setting_Time", pPanel)
elseif _type == "string" then
setting = vgui_Create("SF_Setting_String", pPanel)
elseif _type == "time_toggle" then
setting = vgui_Create("SF_Setting_TimeToggle", pPanel)
elseif _type == "temp" or _type == "temperature" then
setting = vgui_Create("SF_Setting_Float", pPanel)
setting:SetTemperature( true )
elseif _type == "double_number" then
setting = vgui_Create("SF_DDSliderNum", pPanel)
setting:SetSetting(sName[1],sName[2], _type, _desc)
return setting
else
StormFox2.Warning("Unknown Setting Variable: " .. sName .. " [" .. tostring(_type) .. "]")
return
end
if not setting then
StormFox2.Warning("Unknown Setting Variable: " .. sName .. " [" .. tostring(_type) .. "]")
return
end
--local setting = _type == "boolean" and vgui_Create("SFConVar_Bool", board) or vgui_Create("SFConVar", board)
setting:SetSetting(sName, _type, _desc)
return setting
end
local col = {Color(230,230,230), color_white}
local col_dis = Color(0,0,0,55)
local col_dis2 = Color(0,0,0,55)
local bh_col = Color(55,55,55,55)
local sb_col = Color(91,155,213)
local icon = Material("icon16/zoom.png")
local icon_c = Color(255,255,255,180)
local s = 20
local side_button = function(self, w, h)
if self:IsHovered() and not self:GetDisabled() then
surface.SetDrawColor(bh_col)
surface.DrawRect(0,0,w,h)
end
surface.SetDrawColor(self:GetDisabled() and col_dis or color_black)
surface.SetMaterial(self.icon)
surface.DrawTexturedRect(24 - s / 2, (h - s) / 2, s,s)
local t = self.text or "ERROR"
surface.SetFont("DermaDefault")
local tw,th = surface.GetTextSize( t )
surface.SetTextColor(self:GetDisabled() and col_dis2 or color_black)
surface.SetTextPos(48, h / 2 - th / 2)
surface.DrawText(t)
if self._selected then
surface.SetDrawColor(sb_col)
surface.DrawRect(4,4,4,h - 8)
end
end
local t_mat = "icon16/font.png"
local s_mat = "icon16/cog.png"
local s = 60
local n_vc = Color(55,255,55)
local n_bm = Material("vgui/notices/undo")
local PANEL = {}
function PANEL:Init()
-- BG
self:SetTitle("")
function self:SetTitle( str )
self._title = str
end
self:SetSize(64 * 11, 500)
self:Center()
self:DockPadding(0,24,0,0)
function self:Paint(w, h)
surface.SetDrawColor( col[2] )
surface.DrawRect(0,0,w,h)
surface.SetDrawColor( col[1] )
if self.p_left then
surface.DrawRect(0,0,self.p_left:GetWide(),24)
else
surface.DrawRect(0,0,w,24)
end
surface.SetDrawColor(55,55,55,255)
surface.DrawRect(0, 0, w, 24)
local t = self._title or "Window"
surface.SetFont("DermaDefault")
local tw,th = surface.GetTextSize( t )
surface.SetTextColor(color_white)
surface.SetTextPos(5, 12 - th / 2)
surface.DrawText(t)
end
-- Left panel
local p_left = vgui_Create("DPanel", self)
self.p_left = p_left
p_left:SetWide(180)
p_left:Dock( LEFT )
p_left:DockPadding(0,0,0,0)
function p_left:Paint(w, h)
surface.SetDrawColor( col[1] )
surface.DrawRect(0,0,w,h)
end
-- Right panel
local p_right = vgui_Create("DPanel", self)
self.p_right = p_right
p_right:Dock( FILL )
p_right.Paint = empty
p_right.sub = {}
end
function PANEL:CreateLayout( tabs, setting_list )
local p = self
local p_right = self.p_right
local p_left = self.p_left
p_right.sub = {}
for k,v in ipairs( tabs ) do
local p = vgui_Create("DScrollPanel", self.p_right)
p:Dock(FILL)
self.p_right.sub[string.lower(v[1])] = p
p:Hide()
end
p_right.sub["start"]._isstart = true
p_left.buttons = {}
-- Add Start
local b = vgui_Create("DButton", p_left)
b:Dock(TOP)
b:SetTall(40)
b:SetText("")
b.icon = tabs[1][3]
b.text = niceName( language.GetPhrase(tabs[1][2]) )
b.Paint = side_button
p_left.buttons["start"] = b
function b:DoClick()
switch("start", p_right.sub, p_left.buttons, p._cookie)
end
-- Add search bar
local sp = vgui_Create("DPanel", p_left)
p_left.sp = sp
local search_tab = {}
sp:Dock(TOP)
sp:SetTall(40)
function sp:Paint() end
sp.searchbar = vgui_Create("DTextEntry",sp)
sp.searchbar:SetText("")
sp.searchbar:Dock(TOP)
sp.searchbar:SetHeight(20)
sp.searchbar:DockMargin(4,10,4,0)
function sp.searchbar:OptionSelected( sName, page, vguiObj )
local board = switch(page, p_right.sub, p_left.buttons, p._cookie)
if vguiObj then
vguiObj.dMark = 2 + CurTime()
if board then
board:ScrollToChild(vguiObj)
end
timer.Simple(1, function() vguiObj:RequestFocus() end )
end
self:SetText("")
self:KillFocus()
end
function sp.searchbar:OnChange( )
local val = self:GetText()
local tab = {}
if self.result and IsValid(self.result) then
self.result:Remove()
end
local OnlyTitles = val == ""
self.result = vgui_Create("DMenu")
function self.result:OptionSelected( pnl, text )
if not search_tab[pnl.sName] then return end
sp.searchbar:OptionSelected( text, search_tab[pnl.sName][1], search_tab[pnl.sName][2] )
end
for sName, v in pairs( search_tab ) do
local phrase = language.GetPhrase( sName )
if string.find(string.lower(phrase),string.lower(val), nil, true) then
if OnlyTitles and v[3]~=t_mat then continue end
table.insert(tab, {sName, v[1], v[2]})
local op = self.result:AddOption( phrase )
if v[3] then
op:SetIcon(v[3])
end
op.sName = sName
end
end
local x,y = self:LocalToScreen(0,0)
self.result:Open(x, y + self:GetTall())
end
function sp.searchbar:OnGetFocus()
self:OnChange( )
end
function sp.searchbar:OnLoseFocus()
if not self.result then return end
self.result:Remove()
self.result = nil
end
function sp.searchbar:Paint(w,h)
surface.SetDrawColor(color_white)
surface.DrawRect(0,0,w,h)
surface.SetDrawColor(color_black)
surface.DrawOutlinedRect(0,0,w,h)
local text = self:GetText()
if self:IsEditing() then
if math.Round(SysTime() * 2) % 2 == 0 then
text = text .. "|"
end
elseif #text < 1 then
text = "#searchbar_placeholer"
end
surface.SetMaterial(icon)
surface.SetDrawColor(icon_c)
local s = 4
surface.DrawTexturedRect(w - h + s / 2, s / 2, h - s, h - s)
draw.DrawText(text, "DermaDefault", 5, 2, color_black, TEXT_ALIGN_BOTTOM)
end
for i = 2, #tabs do
v = tabs[i]
local b = vgui_Create("DButton", p_left)
b:Dock(TOP)
b:SetTall(40)
b:SetText("")
b.icon = v[3]
b.text = niceName( language.GetPhrase(tabs[i][2]) )
b.sTab = v[1]
b.Paint = side_button
p_left.buttons[string.lower(tabs[i][1])] = b
function b:DoClick()
switch(self.sTab, p_right.sub,p_left.buttons, p._cookie)
end
end
-- Move changelog down
if p_left.buttons["changelog"] then
p_left.buttons["changelog"]:Dock(BOTTOM)
p_left.buttons["changelog"]:SetZPos(1)
end
-- Add workshop button
local b = vgui_Create("DButton", p_left)
b:Dock(BOTTOM)
b:SetTall(40)
b:SetText("")
b.icon = tabs[1][3]
b.text = "Workshop"
b.Paint = side_button
b.r = 180
if StormFox2.NewVersion() then
function b:PaintOver(w,h)
surface.SetDrawColor(color_white)
surface.SetMaterial(n_bm)
if self:IsHovered() then
local dif = math.abs(math.AngleDifference(self.r, 0)) + 5
self.r = (self.r + math.max(0.01,dif) * FrameTime() * 5) % 360
else
self.r = 180
end
surface.DrawTexturedRectRotated(w - 20, h / 2, 20, 20, self.r)
--surface.DrawRect( - w,0,w,h - 1)
draw.DrawText( StormFox2.NewVersion() , "SF_Menu_H2", w - 34 , h / 2 - 8, color_black, TEXT_ALIGN_RIGHT)
end
end
p_left.buttons["workshop"] = b
function b:DoClick()
gui.OpenURL( StormFox2.WorkShopURL )
end
if not StormFox2.WorkShopURL then
b:SetDisabled(true)
end
do
local b = vgui_Create("DButton", p_left)
b:Dock(BOTTOM)
b:SetTall(40)
b:SetText("")
b.icon = Material("stormfox2/discord.png")
b.text = "Discord"
b.Paint = side_button
b.r = 180
p_left.buttons["discord"] = b
function b:DoClick()
gui.OpenURL( "https://discord.gg/mefXXt4u9E" )
end
end
local used = {}
function p:AddSetting( sName, group, _type, sDesc )
if not group then
group = select(2, StormFox2.Setting.GetType(sName))
end
if not group then
group = "misc"
elseif not p_right.sub[group] then
group = "misc"
end
local board = p_right.sub[group]
return board:AddSetting( sName, _type, sDesc )
end
function p:MarkUsed( sName )
used[sName] = true
end
for sBName, pnl in pairs(p_right.sub) do
pnl.sBName = string.lower(sBName)
pnl._other = false
function pnl:AddSetting( sName, _type, sDesc )
if self._other then
self:AddTitle("#other", true)
pnl._other = false
end
local mul = type( sName ) == "table"
if not _type then
_type = StormFox2.Setting.GetType(mul and sName[1] or sName)
end
local setting = addSetting(sName, self, _type, sDesc)
if not setting then return end
if not mul then
if not search_tab["sf_" .. sName] or not self._isstart then
search_tab["sf_" .. sName] = {self.sBName, setting, s_mat}
end
used[sName] = true
else
for k,v in ipairs(sName) do
if not search_tab["sf_" .. v] or not self._isstart then
search_tab["sf_" .. v] = {self.sBName, setting, s_mat}
end
used[v] = true
end
end
--local setting = _type == "boolean" and vgui_Create("SFConVar_Bool", board) or vgui_Create("SFConVar", board)
setting:Dock(TOP)
self:AddItem(setting)
return setting
end
function pnl:AddTitle( sName, bIgnoreSearch )
local dL = vgui_Create("SFTitle", self)
local text = niceName( language.GetPhrase(sName) )
dL:SetText( text )
dL:SetDark(true)
dL:SetFont("SF_Menu_H2")
dL:SizeToContents()
dL:Dock(TOP)
dL:DockMargin(5,self._title and 20 or 0,0,0)
self._title = true
self:AddItem(dL)
if (not search_tab[text] or not self._isstart) and #sName > 0 and not bIgnoreSearch then
search_tab[text] = {self.sBName, dL, t_mat}
end
return dL
end
function pnl:MarkUsed( sName )
p:MarkUsed( sName )
end
end
-- Make the layout
for _,v in ipairs(tabs) do
if not v[4] then continue end
local b = p_right.sub[string.lower(v[1])]
if not b then continue end
v[4]( b )
end
-- Add all other settings
for sBName, pnl in pairs(p_right.sub) do
pnl._other = true
end
for _, sName in ipairs( setting_list ) do
if used[sName] then continue end
p:AddSetting( sName )
end
-- If there are empty setting-pages, remove them
for sBName, pnl in pairs(p_right.sub) do
local n = #pnl:GetChildren()[1]:GetChildren()
if n > 0 then continue end
local b = self.p_left.buttons[sBName]
if IsValid(b) then
b:SetDisabled(true)
end
local p = self.p_right.sub[string.lower(sBName)]
if IsValid(p) then
p:SetDisabled(true)
end
end
-- Add space at bottom
for sBName, pnl in pairs(p_right.sub) do
pnl.bottom = pnl:AddTitle("")
end
end
function PANEL:SetCookie( sCookie )
self._cookie = sCookie
local selected = cookie.GetString(sCookie, "start") or "start"
if not self.p_right.sub[selected] then -- Unknown page, set it to "start"
selected = "start"
end
switch(selected, self.p_right.sub,self.p_left.buttons, sCookie)
end
function PANEL:Select( str_page )
switch(str_page, self.p_right.sub,self.p_left.buttons, self._cookie)
end
derma.DefineControl( "SF_Menu", "", PANEL, "DFrame" )
end
--StormFox2.Menu.OpenController()
-- Test vgui objects
if true then return end
if SF_MENU_TEST then SF_MENU_TEST:Remove() end
SF_MENU_TEST = vgui.Create("DFrame")
SF_MENU_TEST:MakePopup()
SF_MENU_TEST:SetSize(600,500)
SF_MENU_TEST:SetPos(320,ScrH() / 2 - 100)
local function Add(_type, _setting)
local setting = vgui.Create(_type, SF_MENU_TEST)
setting:SetSetting(_setting)
setting:SetSize(50,20)
setting:Dock(TOP)
return setting
end
Add("SF_Setting_Bool", "footprint_enabled")
Add("SF_Setting_String", "footprint_enabled")
Add("SF_Setting_Float", "overwrite_extra_darkness")
Add("SF_Setting_Int", "window_distance"):SetTemperature(true)
Add("SF_Setting_FloatSpecial", "window_distance")
Add("SF_Setting_Enum", "12h_display")
Add("SF_Setting_Time", "sunrise")
Add("SF_Setting_TimeToggle", "sunrise")