

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();

	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:GetRange()

	return ( self:GetMax() - self:GetMin() )

end



function PANEL:IdealZoom()



	return 400 / self:GetRange();



end



function PANEL:OnMousePressed( mousecode )



	if ( self:GetZoom() == 0 ) then self:SetZoom( self:IdealZoom() ) end



	self:SetActive( true )

	self:MouseCapture( true )



	self:LockCursor()

	self:SetCursor( "none" )



	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 = 20



	if ( self:GetDecimals() ) then

		maxzoom = 10000

	end

	

	zoom = math.Clamp( zoom + ((y * -0.6) / ControlScale), 0.01, maxzoom );

	self:SetZoom( zoom )



	local value = self:GetFloatValue()

	value = math.Clamp( value + (x * ControlScale * 0.002), self:GetMin(), self:GetMax() );

	self:SetFloatValue( value )



	self:LockCursor()



	self:OnValueChanged( value )

	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.mod( value * self:GetZoom(), size );

	local top = h * 0.4;

	local nh = h - (top);



	local frame_min = realmid + min * self:GetZoom()

	local frame_width = range * self:GetZoom()



	surface.SetDrawColor( 0, 0, 0, alpha )

	surface.DrawRect( frame_min, y + top, frame_width, 2 );



	surface.SetFont( "DermaDefault" )

	

	for n = -span, span, 1 do



		local nx = ((mid) + n * size)

		

		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()

	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 )



	--

	-- Draw the first

	--

	local nx = realmid + min * self:GetZoom()

	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



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



	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 )

	surface.DrawRect( x + w * 0.5 - ((value-min) * self:GetZoom()), y + h *0.4, range * self:GetZoom(), h )



	-- how 2 loop

	self:DrawNotches( 10000, x, y, w, h, range, value, min, max )

	self:DrawNotches( 1000, x, y, w, h, range, value, min, max )

	self:DrawNotches( 100, x, y, w, h, range, value, min, max )

	self:DrawNotches( 10, x, y, w, h, range, value, min, max )

	

	if ( self:GetDecimals() ) then

		self:DrawNotches( 1, x, y, w, h, range, value, min, max )

		self:DrawNotches( 0.1, x, y, w, h, range, value, min, max )

		self:DrawNotches( 0.01, x, y, w, h, range, value, min, max )

		self:DrawNotches( 0.001, 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.SetTextColor( 255, 255, 255, 255 )

	surface.SetFont( "DermaLarge" )

	

	local str = Format( "%i", self:GetFloatValue() );

	if ( self:GetDecimals() ) then

		str = Format( "%.2f", self:GetFloatValue() );

	end

	str = string.Comma( str )



	local tw, th = surface.GetTextSize( str )

	surface.SetTextPos( x + w * 0.5 - tw * 0.5, y + h - th - 5 )

	surface.DrawText( str )



	DisableClipping( false )



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



	render.SetScissorRect( x, y, x+w, y+h, true )

		self:DrawScreen( x, y, w, h )

	render.SetScissorRect( x, y, w, h, false )



end



--

-- For your pleasure.

--

function PANEL:OnValueChanged() 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 )