--[[   _                                

	( )                               

   _| |   __   _ __   ___ ___     _ _ 

 /'_` | /'__`\( '__)/' _ ` _ `\ /'_` )

( (_| |(  ___/| |   | ( ) ( ) |( (_| |

`\__,_)`\____)(_)   (_) (_) (_)`\__,_) 



	DTree

	

	

	

--]]

	

local PANEL = {}



AccessorFunc( PANEL, "m_pRoot", 				"Root" )



AccessorFunc( PANEL, "m_pParentNode", 			"ParentNode" )



AccessorFunc( PANEL, "m_strFolder", 			"Folder" )

AccessorFunc( PANEL, "m_strFileName", 			"FileName" )

AccessorFunc( PANEL, "m_strPathID", 			"PathID" )

AccessorFunc( PANEL, "m_strWildCard", 			"WildCard" )

AccessorFunc( PANEL, "m_bNeedsPopulating", 		"NeedsPopulating" )

AccessorFunc( PANEL, "m_bShowFiles", 			"ShowFiles", 			FORCE_BOOL )



AccessorFunc( PANEL, "m_bDirty", 				"Dirty", 				FORCE_BOOL )

AccessorFunc( PANEL, "m_bNeedsChildSearch",		"NeedsChildSearch", 	FORCE_BOOL )



AccessorFunc( PANEL, "m_bForceShowExpander",	"ForceShowExpander", 	FORCE_BOOL )

AccessorFunc( PANEL, "m_bHideExpander",			"HideExpander", 		FORCE_BOOL )

AccessorFunc( PANEL, "m_bDoubleClickToOpen",	"DoubleClickToOpen", 	FORCE_BOOL )



AccessorFunc( PANEL, "m_bLastChild",			"LastChild", 	FORCE_BOOL )

AccessorFunc( PANEL, "m_bDrawLines",			"DrawLines", 	FORCE_BOOL )

AccessorFunc( PANEL, "m_strDraggableName", 		"DraggableName" )





--[[---------------------------------------------------------

   Name: Init

-----------------------------------------------------------]]

function PANEL:Init()



	self:SetDoubleClickToOpen( true );

	

	self.Label = vgui.Create( "DTree_Node_Button", self )

	self.Label:SetDragParent( self );

	self.Label.DoClick = function() self:InternalDoClick() end

	self.Label.DoDoubleClick = function() self:InternalDoClick() end

	self.Label.DoRightClick = function() self:InternalDoRightClick() end

	self.Label.DragHover = function( s, t ) self:DragHover( t ) end



	self.Expander = vgui.Create( "DExpandButton", self )

	self.Expander.DoClick = function() self:SetExpanded( !self.m_bExpanded ) end

	self.Expander:SetVisible( false )

	

	self.Icon = vgui.Create( "DImage", self )

	self.Icon:SetImage( "icon16/folder.png" )

	self.Icon:SizeToContents()

	

	self.animSlide = Derma_Anim( "Anim", self, self.AnimSlide )

	

	self.fLastClick = SysTime();

	

	self:SetDrawLines( false )

	self:SetLastChild( false )



end



function PANEL:IsRootNode()

	return self.m_pRoot == self.m_pParentNode

end



--[[---------------------------------------------------------

   Name: DoClick

-----------------------------------------------------------]]

function PANEL:InternalDoClick()



	self:GetRoot():SetSelectedItem( self )



	if ( self:DoClick() ) then return end

	if ( self:GetRoot():DoClick( self ) ) then return end

	

	if ( !self.m_bDoubleClickToOpen || (SysTime() - self.fLastClick < 0.3) ) then

		self:SetExpanded( !self.m_bExpanded )

	end

		

	self.fLastClick = SysTime()

	

end



function PANEL:OnNodeSelected( node )



	local parent = self:GetParentNode()

	if ( IsValid( parent ) && parent.OnNodeSelected ) then

		parent:OnNodeSelected( node )

	end



end



--[[---------------------------------------------------------

   Name: InternalDoRightClick

-----------------------------------------------------------]]

function PANEL:InternalDoRightClick()



	if ( self:DoRightClick() ) then return end

	if ( self:GetRoot():DoRightClick( self ) ) then return end



end



--[[---------------------------------------------------------

   Name: DoClick

-----------------------------------------------------------]]

function PANEL:DoClick()

	return false

end



--[[---------------------------------------------------------

   Name: DoRightClick

-----------------------------------------------------------]]

function PANEL:DoRightClick()

	return false

end



--[[---------------------------------------------------------

   Name: AnimSlide

-----------------------------------------------------------]]

function PANEL:AnimSlide( anim, delta, data )

	

	if ( !self.ChildNodes ) then anim:Stop() return end

	

	if ( anim.Started ) then

		data.To = self:GetTall()

		data.Visible = self.ChildNodes:IsVisible()

	end

	

	if ( anim.Finished ) then

		self:InvalidateLayout()

		self.ChildNodes:SetVisible( data.Visible )

		self:SetTall( data.To )

		self:GetParentNode():ChildExpanded()

	return end



	self.ChildNodes:SetVisible( true )

	

	self:SetTall( Lerp( delta, data.From, data.To ) )

	

	self:GetParentNode():ChildExpanded()

	

end



function PANEL:SetIcon( str )



	if ( !str ) then return end

	if ( str == "" ) then return end



	self.Icon:SetImage( str )

end



--[[---------------------------------------------------------

   Name: ShowIcons

-----------------------------------------------------------]]

function PANEL:ShowIcons()

	return self:GetParentNode():ShowIcons()

end



--[[---------------------------------------------------------

   Name: GetLineHeight

-----------------------------------------------------------]]

function PANEL:GetLineHeight()

	return self:GetParentNode():GetLineHeight()

end





--[[---------------------------------------------------------

   Name: GetIndentSize

-----------------------------------------------------------]]

function PANEL:GetIndentSize()

	return self:GetParentNode():GetIndentSize()

end



--[[---------------------------------------------------------

   Name: strSomething

-----------------------------------------------------------]]

function PANEL:SetText( strName )



	self.Label:SetText( strName )



end



--[[---------------------------------------------------------

   Name: ExpandRecurse

-----------------------------------------------------------]]

function PANEL:ExpandRecurse( bExpand )



	self:SetExpanded( bExpand, true )

	

	if ( !self.ChildNodes ) then return end

	

	for k, Child in pairs( self.ChildNodes:GetItems() ) do

		if ( Child.ExpandRecurse ) then

			Child:ExpandRecurse( bExpand )

		end

	end



end



--[[---------------------------------------------------------

   Name: ExpandTo

-----------------------------------------------------------]]

function PANEL:ExpandTo( bExpand )



	self:SetExpanded( bExpand, true )

	self:GetParentNode():ExpandTo( bExpand )



end





--[[---------------------------------------------------------

   Name: SetExpanded

-----------------------------------------------------------]]

function PANEL:SetExpanded( bExpand, bSurpressAnimation )



	self:GetParentNode():ChildExpanded( bExpand )

	self.Expander:SetExpanded( bExpand ) 

	self.m_bExpanded = bExpand

	self:InvalidateLayout( true )

	

	if ( !self.ChildNodes ) then return end



	local StartTall = self:GetTall()

	self.animSlide:Stop()



	-- Populate the child folders..

	if ( bExpand ) then

		if ( self:PopulateChildrenAndSelf( true ) ) then 

		

			-- Could really do with a 'loading' thing here

		

			return 

		end

	end

	

	if ( self.ChildNodes ) then

		self.ChildNodes:SetVisible( bExpand )

		if ( bExpand ) then

			self.ChildNodes:InvalidateLayout( true )

		end

	end

	

	self:InvalidateLayout( true )

			

	--

	-- Do animation..

	if ( !bSurpressAnimation ) then

		self.animSlide:Start( 0.3, { From = StartTall } )

		self.animSlide:Run()

	end

	

end



--[[---------------------------------------------------------

   Name: ChildExpanded

-----------------------------------------------------------]]

function PANEL:ChildExpanded( bExpand )



	self.ChildNodes:InvalidateLayout( true )

	self:InvalidateLayout( true )

	self:GetParentNode():ChildExpanded( bExpand )

	

end



--[[---------------------------------------------------------

   Name: Paint

-----------------------------------------------------------]]

function PANEL:Paint()

end



--[[---------------------------------------------------------

   Name: HasChildren

-----------------------------------------------------------]]

function PANEL:HasChildren()

	

	if ( !IsValid( self.ChildNodes ) ) then return false end

	return self.ChildNodes:HasChildren()

	

end





function PANEL:DoChildrenOrder()



	if ( !self.ChildNodes ) then return end

	

	local last = table.Count( self.ChildNodes:GetChildren() )

	for k, Child in pairs( self.ChildNodes:GetChildren() ) do

		Child:SetLastChild( k == last )

	end



end



function PANEL:PerformRootNodeLayout()



	self.Expander:SetVisible( false )

	self.Label:SetVisible( false )

	self.Icon:SetVisible( false )

	

	if ( IsValid( self.ChildNodes ) ) then

	

		self.ChildNodes:Dock( TOP )

		self:SetTall( self.ChildNodes:GetTall() )

		

	end

	

end



--[[---------------------------------------------------------

   Name: PerformLayout

-----------------------------------------------------------]]

function PANEL:PerformLayout()



	if ( self:IsRootNode() ) then

		return self:PerformRootNodeLayout(); 

	end

	

	if ( self.animSlide:Active() ) then return end

	

	local LineHeight = self:GetLineHeight()

	

	if ( self.m_bHideExpander ) then

	

		self.Expander:SetPos( -11, 0 );

		self.Expander:SetSize( 15, 15 )

		self.Expander:SetVisible( false );

	

	else

	

		self.Expander:SetPos( 2, 0 )

		self.Expander:SetSize( 15, 15 )

		self.Expander:SetVisible( self:HasChildren() || self:GetForceShowExpander() )

		self.Expander:SetZPos( 10 )

		

	end

		

	self.Label:StretchToParent( 0, nil, 0, nil )

	self.Label:SetTall( LineHeight )

	

	if ( self:ShowIcons() ) then

		self.Icon:SetVisible( true )

		self.Icon:SetPos( self.Expander.x + self.Expander:GetWide() + 4, (LineHeight - self.Icon:GetTall()) * 0.5 )

		self.Label:SetTextInset( self.Icon.x + self.Icon:GetWide() + 4, 0 )

	else

		self.Icon:SetVisible( false )

		self.Label:SetTextInset( self.Expander.x + self.Expander:GetWide() + 4, 0 )

	end

	

	if ( !self.ChildNodes || !self.ChildNodes:IsVisible() ) then 

		self:SetTall( LineHeight ) 

	return end

	

	self.ChildNodes:SizeToContents()

	self:SetTall( LineHeight + self.ChildNodes:GetTall() )

	

	self.ChildNodes:StretchToParent( LineHeight, LineHeight, 0, 0 )

	

	self:DoChildrenOrder()

	

end



--[[---------------------------------------------------------

   Name: CreateChildNodes

-----------------------------------------------------------]]

function PANEL:CreateChildNodes()



	if ( self.ChildNodes ) then return end



	self.ChildNodes = vgui.Create( "DListLayout", self )

	self.ChildNodes:SetDropPos( "852" )

	self.ChildNodes:SetVisible( self.m_bExpanded )

	self.ChildNodes.OnChildRemoved = function()

	

		self.ChildNodes:InvalidateLayout()

		

		if ( !self.ChildNodes:HasChildren() ) then

			self:SetExpanded( false )

		end

	

	end

	

	self.ChildNodes.OnModified = function()

	

		self:OnModified()

	

	end

	

	self:InvalidateLayout()



end



--[[---------------------------------------------------------

   Name: AddPanel

-----------------------------------------------------------]]

function PANEL:AddPanel( pPanel )

	

	self:CreateChildNodes()

	

	self.ChildNodes:Add( pPanel )

	self:InvalidateLayout()

	

end





--[[---------------------------------------------------------

   Name: AddNode

-----------------------------------------------------------]]

function PANEL:AddNode( strName, strIcon )

	

	self:CreateChildNodes()

	

	local pNode = vgui.Create( "DTree_Node", self )

		pNode:SetText( strName )

		pNode:SetParentNode( self )

		pNode:SetRoot( self:GetRoot() )

		pNode:SetIcon( strIcon )

		pNode:SetDrawLines( !self:IsRootNode() )

		

		self:InstallDraggable( pNode )			

	

	self.ChildNodes:Add( pNode )

	self:InvalidateLayout()

	

	return pNode

	

end



--[[---------------------------------------------------------

   Name: InsertNode

-----------------------------------------------------------]]

function PANEL:InsertNode( pNode )

	

	self:CreateChildNodes()

	

	pNode:SetParentNode( self )

	pNode:SetRoot( self:GetRoot() )

	self:InstallDraggable( pNode )			

	

	self.ChildNodes:Add( pNode )

	self:InvalidateLayout()

	

	return pNode

	

end



--[[---------------------------------------------------------

   Name: InstallDraggable

-----------------------------------------------------------]]

function PANEL:InstallDraggable( pNode )



	local DragName = self:GetDraggableName()

	if ( !DragName ) then return end

	

	-- Make this node draggable

	pNode:SetDraggableName( DragName )

	pNode:Droppable( DragName );	

	

	-- Allow item dropping onto us

	self.ChildNodes:MakeDroppable( DragName, true, true )



end



function PANEL:DroppedOn( pnl )

	

	self:InsertNode( pnl )

	self:SetExpanded( true )

	

end



--[[---------------------------------------------------------

   Name: AddFolder

-----------------------------------------------------------]]

function PANEL:AddFolder( strName, strFolder, strPath, bShowFiles, strWildCard, bDontForceExpandable )



	local node = self:AddNode( strName )

	node:MakeFolder( strFolder, strPath, bShowFiles, strWildCard, bDontForceExpandable )

	return node;



end







--[[---------------------------------------------------------

   Name: MakeFolder

-----------------------------------------------------------]]

function PANEL:MakeFolder( strFolder, strPath, bShowFiles, strWildCard, bDontForceExpandable )

	

	

	strWildCard = strWildCard or "*"

	

	-- Store the data

	self:SetNeedsPopulating( true )

	self:SetWildCard( strWildCard )

	self:SetFolder( strFolder )

	self:SetPathID( strPath )

	self:SetShowFiles( bShowFiles or false )

	

	self:CreateChildNodes()

	self:SetNeedsChildSearch( true )

	

	if ( !bDontForceExpandable ) then

		self:SetForceShowExpander( true )

	end

	

end



--[[---------------------------------------------------------

   Name: FilePopulateCallback

-----------------------------------------------------------]]

function PANEL:FilePopulateCallback( files, folders, foldername, path, bAndChildren )



	local showfiles = self:GetShowFiles()



	self.ChildNodes:InvalidateLayout( true )

	

	local FileCount = 0

	

	if ( folders ) then

	

		for k, File in SortedPairsByValue( folders ) do

		

			local Node = self:AddNode( File )

			Node:MakeFolder( foldername .. "/" .. File, path, showfiles, wildcard, true )

			FileCount = FileCount + 1

		

		end

		

	end

	

	if ( showfiles ) then

	

		for k, File in SortedPairs( files ) do

		

			local icon = "icon16/page_white.png"

		

			local Node = self:AddNode( File, icon )

			Node:SetFileName( foldername .. "/" .. File )

			FileCount = FileCount + 1

		

		end

		

	end

	

	if ( FileCount == 0 ) then

		

		self.ChildNodes:Remove()

		self.ChildNodes = nil

		

		self:SetNeedsPopulating( false)

		self:SetShowFiles( nil )

		self:SetWildCard( nil )

	

		self:InvalidateLayout()

		

		self.Expander:SetExpanded( true )

		

	return end

	

	self:InvalidateLayout()

	

end



--[[---------------------------------------------------------

   Name: FilePopulate

-----------------------------------------------------------]]

function PANEL:FilePopulate( bAndChildren, bExpand )



	if ( !self:GetNeedsPopulating() ) then return end



	local folder = self:GetFolder()

	local path = self:GetPathID()

	local wildcard = self:GetWildCard()

	

	if ( !folder || !wildcard || !path ) then return false end

	

	local files, folders = file.Find( folder .. "/" .. wildcard, path )

	

	self:SetNeedsPopulating( false )

	self:SetNeedsChildSearch( false )

	

	self:FilePopulateCallback( files, folders, folder, path, bAndChildren ) 

	

	if ( bExpand ) then

		self:SetExpanded( true ) 

	end

												

	return true



end



--[[---------------------------------------------------------

   Name: PopulateChildren

-----------------------------------------------------------]]

function PANEL:PopulateChildren()



	for k, v in pairs( self.ChildNodes:GetChildren() ) do

		timer.Simple( k * 0.1, function()

		

			if ( IsValid( v ) ) then

				v:FilePopulate( false )

			end

			

		end )

	end



end



--[[---------------------------------------------------------

   Name: PopulateChildrenAndSelf

-----------------------------------------------------------]]

function PANEL:PopulateChildrenAndSelf( bExpand )



	-- Make sure we're populated

	if ( self:FilePopulate( true, bExpand ) ) then return true end

	

	self:PopulateChildren()



end



--[[---------------------------------------------------------

   Name: AddNode

-----------------------------------------------------------]]

function PANEL:SetSelected( b )

	

	self.Label:SetSelected( b )

	self.Label:InvalidateLayout()

	

end



--[[---------------------------------------------------------

   Name: Think

-----------------------------------------------------------]]

function PANEL:Think()



	self.animSlide:Run()



end



--

-- DragHoverClick

--

function PANEL:DragHoverClick( HoverTime )



	if ( !self.m_bExpanded ) then 

		self:SetExpanded( true )

	end

	

	if ( self:GetRoot():GetClickOnDragHover() ) then

	

		self:InternalDoClick();

	

	end



end





function PANEL:MoveToTop()



	local parent = self:GetParentNode();

	if ( !IsValid(parent) ) then return end

	

	self:GetParentNode():MoveChildTo( self, 1 )



end



function PANEL:MoveChildTo( child )



	self.ChildNodes:InsertAtTop( child )



end



function PANEL:GetText()

	return self.Label:GetText()

end



function PANEL:GetIcon()

	return self.Icon:GetImage()

end



function PANEL:CleanList()



	for k, panel in pairs( self.Items ) do

	

		if ( !IsValid( panel ) || panel:GetParent() != self.pnlCanvas ) then

			self.Items[k] = nil

		end

	

	end



end



function PANEL:Insert( pNode, pNodeNextTo, bBefore )



	pNode:SetParentNode( self )

	pNode:SetRoot( self:GetRoot() )

	

	self:CreateChildNodes()

	

	if ( bBefore ) then

		self.ChildNodes:InsertBefore( pNodeNextTo, pNode )

	else

		self.ChildNodes:InsertAfter( pNodeNextTo, pNode )

	end

	

	self:InvalidateLayout()



end



function PANEL:LeaveTree( pnl )



	self.ChildNodes:RemoveItem( pnl, true )

	self:InvalidateLayout()



end





function PANEL:OnModified()



	// Override Me



end



function PANEL:GetChildNode( iNum )



	if ( !IsValid( self.ChildNodes )  ) then return end

	return self.ChildNodes:GetChild( iNum )



end



--[[---------------------------------------------------------



-----------------------------------------------------------]]

function PANEL:Paint( w, h )



	derma.SkinHook( "Paint", "TreeNode", self, w, h )



end



--[[---------------------------------------------------------



-----------------------------------------------------------]]

function PANEL:Copy()



	local copy = vgui.Create( "DTree_Node", self:GetParent() )

	copy:SetText( self:GetText() )

	copy:SetIcon( self:GetIcon() )

	copy:SetRoot( self:GetRoot() )

	copy:SetParentNode( self:GetParentNode() )

	

	if ( self.ChildNodes ) then

	

		for k, v in pairs( self.ChildNodes:GetChildren() ) do

		

			local childcopy = v:Copy()

			copy:InsertNode( childcopy )

					

		end

		

	end

	

	self:SetupCopy( copy )

	

	return copy



end



--[[---------------------------------------------------------



-----------------------------------------------------------]]

function PANEL:SetupCopy( copy )



	// TODO.



end



derma.DefineControl( "DTree_Node", "Tree Node", PANEL, "DPanel" )