mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 13:23:46 +03:00
382 lines
8.7 KiB
Lua
382 lines
8.7 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/
|
|
--]]
|
|
|
|
|
|
DEFINE_BASECLASS( "DImageButton" )
|
|
|
|
local g_Active = nil
|
|
|
|
local PANEL = {}
|
|
|
|
AccessorFunc( PANEL, "m_numMin", "Min" )
|
|
AccessorFunc( PANEL, "m_numMax", "Max" )
|
|
AccessorFunc( PANEL, "m_Zoom", "Zoom" )
|
|
AccessorFunc( PANEL, "m_fFloatValue", "FloatValue" )
|
|
AccessorFunc( PANEL, "m_bActive", "Active" )
|
|
AccessorFunc( PANEL, "m_iDecimals", "Decimals" )
|
|
AccessorFunc( PANEL, "m_bDrawScreen", "ShouldDrawScreen" )
|
|
|
|
Derma_Install_Convar_Functions( PANEL )
|
|
|
|
function PANEL:Init()
|
|
|
|
self:SetMin( 0 )
|
|
self:SetMax( 10 )
|
|
self:SetZoom( 0 )
|
|
self:SetDecimals( 2 )
|
|
self:SetFloatValue( 1.5 )
|
|
self:SetShouldDrawScreen( false )
|
|
|
|
self.MouseX = 0
|
|
self.MouseY = 0
|
|
self.UnderMaterial = Material( "gui/numberscratch_under.png" )
|
|
self.CoverMaterial = Material( "gui/numberscratch_cover.png" )
|
|
|
|
self:SetImage( "icon16/scratchnumber.png" )
|
|
self:SetStretchToFit( false )
|
|
self:SetSize( 16, 16 )
|
|
|
|
self:SetCursor( "sizewe" )
|
|
|
|
end
|
|
|
|
function PANEL:SetValue( val )
|
|
|
|
local val = tonumber( val )
|
|
if ( val == nil ) then return end
|
|
if ( val == self:GetFloatValue() ) then return end
|
|
|
|
self:SetFloatValue( val )
|
|
self:OnValueChanged( val )
|
|
self:UpdateConVar()
|
|
|
|
end
|
|
|
|
function PANEL:SetFraction( fFraction )
|
|
|
|
self:SetFloatValue( self:GetMin() + ( fFraction * self:GetRange() ) )
|
|
|
|
end
|
|
|
|
function PANEL:GetFraction()
|
|
|
|
return ( self:GetFloatValue() - self:GetMin() ) / self:GetRange()
|
|
|
|
end
|
|
|
|
function PANEL:GetDecimals()
|
|
|
|
return self.m_iDecimals or 0
|
|
|
|
end
|
|
|
|
function PANEL:GetRange()
|
|
return self:GetMax() - self:GetMin()
|
|
end
|
|
|
|
function PANEL:IdealZoom()
|
|
|
|
return 400 / self:GetRange()
|
|
|
|
end
|
|
|
|
function PANEL:OnMousePressed( mousecode )
|
|
|
|
if ( !self:IsEnabled() ) then return end
|
|
|
|
if ( self:GetZoom() == 0 ) then self:SetZoom( self:IdealZoom() ) end
|
|
|
|
self:SetActive( true )
|
|
self:MouseCapture( true )
|
|
|
|
self:LockCursor()
|
|
|
|
-- Temporary fix for Linux
|
|
-- Something keeps snapping the cursor to the center of the screen when it is invisible
|
|
-- and we definitely don't want that, let's keep the cursor visible for now
|
|
if ( !system.IsLinux() ) then
|
|
self:SetCursor( "none" )
|
|
end
|
|
|
|
self:SetShouldDrawScreen( mousecode == MOUSE_LEFT )
|
|
|
|
g_Active = self
|
|
|
|
end
|
|
|
|
function PANEL:OnMouseReleased( mousecode )
|
|
|
|
g_Active = nil
|
|
|
|
self:SetActive( false )
|
|
self:MouseCapture( false )
|
|
self:SetCursor( "sizewe" )
|
|
|
|
end
|
|
|
|
function PANEL:LockCursor()
|
|
|
|
local x, y = self:LocalToScreen( math.floor( self:GetWide() * 0.5 ), math.floor( self:GetTall() * 0.5 ) )
|
|
input.SetCursorPos( x, y )
|
|
|
|
end
|
|
|
|
function PANEL:OnCursorMoved( x, y )
|
|
|
|
if ( !self:GetActive() ) then return end
|
|
|
|
x = x - math.floor( self:GetWide() * 0.5 )
|
|
y = y - math.floor( self:GetTall() * 0.5 )
|
|
|
|
local zoom = self:GetZoom()
|
|
|
|
local ControlScale = 100 / zoom
|
|
|
|
local maxzoom = 10 ^ ( 1 + self:GetDecimals() )
|
|
|
|
zoom = math.Clamp( zoom + ( ( y * -0.6 ) / ControlScale ), 0.01, maxzoom )
|
|
if ( !input.IsKeyDown( KEY_LSHIFT ) ) then self:SetZoom( zoom ) end
|
|
|
|
local oldValue = self:GetFloatValue()
|
|
local value = self:GetFloatValue()
|
|
value = math.Clamp( value + ( x * ControlScale * 0.002 ), self:GetMin(), self:GetMax() )
|
|
self:SetFloatValue( value )
|
|
|
|
self:LockCursor()
|
|
|
|
if ( oldValue != value ) then self:OnValueChanged( value ) end
|
|
self:UpdateConVar()
|
|
|
|
end
|
|
|
|
function PANEL:GetTextValue()
|
|
|
|
local iDecimals = self:GetDecimals()
|
|
if ( iDecimals == 0 ) then
|
|
return Format( "%i", self:GetFloatValue() )
|
|
end
|
|
|
|
return Format( "%." .. iDecimals .. "f", self:GetFloatValue() )
|
|
|
|
end
|
|
|
|
function PANEL:UpdateConVar()
|
|
|
|
self:ConVarChanged( self:GetTextValue() )
|
|
|
|
end
|
|
|
|
function PANEL:DrawNotches( level, x, y, w, h, range, value, min, max )
|
|
|
|
local size = level * self:GetZoom()
|
|
if ( size < 5 ) then return end
|
|
if ( size > w * 2 ) then return end
|
|
|
|
local alpha = 255
|
|
|
|
if ( size < 150 ) then alpha = alpha * ( ( size - 2 ) / 140 ) end
|
|
if ( size > ( w * 2 ) - 100 ) then alpha = alpha * ( 1 - ( ( size - ( w - 50 ) ) / 50 ) ) end
|
|
|
|
local halfw = w * 0.5
|
|
local span = math.ceil( w / size )
|
|
local realmid = x + w * 0.5 - ( value * self:GetZoom() )
|
|
local mid = x + w * 0.5 - math.fmod( value * self:GetZoom(), size )
|
|
local top = h * 0.4
|
|
local nh = h - top
|
|
|
|
local frame_min = math.floor( realmid + min * self:GetZoom() )
|
|
local frame_width = math.ceil( range * self:GetZoom() )
|
|
local targetW = math.min( w - math.max( 0, frame_min - x ), frame_width - math.max( 0, x - frame_min ) )
|
|
|
|
surface.SetDrawColor( 0, 0, 0, alpha )
|
|
surface.DrawRect( math.max( x, frame_min ), y + top, targetW, 2 )
|
|
|
|
surface.SetFont( "DermaDefault" )
|
|
|
|
for n = -span, span, 1 do
|
|
|
|
local nx = mid + n * size
|
|
|
|
if ( nx > x + w or nx < x ) then continue end
|
|
|
|
local dist = 1 - ( math.abs( halfw - nx + x ) / w )
|
|
|
|
local val = ( nx - realmid ) / self:GetZoom()
|
|
|
|
if ( val <= min + 0.001 ) then continue end
|
|
if ( val >= max - 0.001 ) then continue end
|
|
|
|
surface.SetDrawColor( 0, 0, 0, alpha * dist )
|
|
surface.SetTextColor( 0, 0, 0, alpha * dist )
|
|
|
|
surface.DrawRect( nx, y + top, 2, nh )
|
|
|
|
local tw, th = surface.GetTextSize( val )
|
|
|
|
surface.SetTextPos( nx - ( tw * 0.5 ), y + top - th )
|
|
surface.DrawText( val )
|
|
|
|
end
|
|
|
|
surface.SetDrawColor( 0, 0, 0, alpha )
|
|
surface.SetTextColor( 0, 0, 0, alpha )
|
|
|
|
--
|
|
-- Draw the last one.
|
|
--
|
|
local nx = realmid + max * self:GetZoom()
|
|
if ( nx < x + w ) then
|
|
surface.DrawRect( nx, y + top, 2, nh )
|
|
|
|
local val = max
|
|
local tw, th = surface.GetTextSize( val )
|
|
|
|
surface.SetTextPos( nx - ( tw * 0.5 ), y + top - th )
|
|
surface.DrawText( val )
|
|
end
|
|
|
|
--
|
|
-- Draw the first
|
|
--
|
|
local nx = realmid + min * self:GetZoom()
|
|
if ( nx > x ) then
|
|
surface.DrawRect( nx, y + top, 2, nh )
|
|
|
|
local val = min
|
|
local tw, th = surface.GetTextSize( val )
|
|
|
|
surface.SetTextPos( nx - ( tw * 0.5 ), y + top - th )
|
|
surface.DrawText( val )
|
|
end
|
|
|
|
end
|
|
|
|
function PANEL:Think()
|
|
|
|
if ( !self:GetActive() ) then
|
|
self:ConVarNumberThink()
|
|
end
|
|
|
|
end
|
|
|
|
function PANEL:IsEditing()
|
|
return self:GetActive()
|
|
end
|
|
|
|
function PANEL:DrawScreen( x, y, w, h )
|
|
|
|
if ( !self:GetShouldDrawScreen() ) then return end
|
|
|
|
local wasEnabled = DisableClipping( true )
|
|
|
|
--
|
|
-- Background
|
|
--
|
|
surface.SetMaterial( self.UnderMaterial )
|
|
surface.SetDrawColor( 255, 255, 255, 255 )
|
|
surface.DrawTexturedRect( x, y, w, h )
|
|
|
|
local min = self:GetMin()
|
|
local max = self:GetMax()
|
|
local range = self:GetMax() - self:GetMin()
|
|
local value = self:GetFloatValue()
|
|
|
|
--
|
|
-- Background colour block
|
|
--
|
|
surface.SetDrawColor( 255, 250, 180, 100 )
|
|
local targetX = x + w * 0.5 - ( ( value - min ) * self:GetZoom() )
|
|
local targetW = range * self:GetZoom()
|
|
targetW = targetW - math.max( 0, x - targetX )
|
|
targetW = math.min( targetW, w - math.max( 0, targetX - x ) )
|
|
surface.DrawRect( math.max( targetX, x ) + 3, y + h * 0.4, targetW - 6, h * 0.6 )
|
|
|
|
for i = 1, 4 do
|
|
self:DrawNotches( 10 ^ i, x, y, w, h, range, value, min, max )
|
|
end
|
|
|
|
for i = 0, self:GetDecimals() do
|
|
self:DrawNotches( 1 / 10 ^ i, x, y, w, h, range, value, min, max )
|
|
end
|
|
|
|
--
|
|
-- Cover
|
|
--
|
|
surface.SetMaterial( self.CoverMaterial )
|
|
surface.SetDrawColor( 255, 255, 255, 255 )
|
|
surface.DrawTexturedRect( x, y, w, h )
|
|
|
|
--
|
|
-- Text Value
|
|
--
|
|
surface.SetFont( "DermaLarge" )
|
|
local str = self:GetTextValue()
|
|
str = string.Comma( str )
|
|
local tw, th = surface.GetTextSize( str )
|
|
|
|
draw.RoundedBoxEx( 8, x + w * 0.5 - tw / 2 - 10, y + h - 43, tw + 20, 39, Color( 0, 186, 255, 255 ), true, true, false, false )
|
|
|
|
surface.SetTextColor( 255, 255, 255, 255 )
|
|
surface.SetTextPos( x + w * 0.5 - tw * 0.5, y + h - th - 6 )
|
|
surface.DrawText( str )
|
|
|
|
DisableClipping( wasEnabled )
|
|
|
|
end
|
|
|
|
function PANEL:PaintScratchWindow()
|
|
|
|
if ( !self:GetActive() ) then return end
|
|
|
|
if ( self:GetZoom() == 0 ) then self:SetZoom( self:IdealZoom() ) end
|
|
|
|
local w, h = 512, 256
|
|
local x, y = self:LocalToScreen( 0, 0 )
|
|
|
|
x = x + self:GetWide() * 0.5 - w * 0.5
|
|
y = y - 8 - h
|
|
|
|
if ( x + w + 32 > ScrW() ) then x = ScrW() - w - 32 end
|
|
if ( y + h + 32 > ScrH() ) then y = ScrH() - h - 32 end
|
|
if ( x < 32 ) then x = 32 end
|
|
if ( y < 32 ) then y = 32 end
|
|
|
|
if ( render ) then render.SetScissorRect( x, y, x + w, y + h, true ) end
|
|
self:DrawScreen( x, y, w, h )
|
|
if ( render ) then render.SetScissorRect( x, y, w, h, false ) end
|
|
|
|
end
|
|
|
|
--
|
|
-- For your pleasure.
|
|
--
|
|
function PANEL:OnValueChanged( value )
|
|
end
|
|
|
|
PANEL.AllowAutoRefresh = true
|
|
|
|
function PANEL:GenerateExample()
|
|
|
|
-- The concommand derma_controls currently runs in the menu realm
|
|
-- DNumberScratch uses the render library which is currently unavailable in this realm
|
|
-- Therefor we cannot generate an example without spitting errors
|
|
|
|
end
|
|
|
|
derma.DefineControl( "DNumberScratch", "", PANEL, "DImageButton" )
|
|
|
|
hook.Add( "DrawOverlay", "DrawNumberScratch", function()
|
|
|
|
if ( !IsValid( g_Active ) ) then return end
|
|
|
|
g_Active:PaintScratchWindow()
|
|
|
|
end )
|