Jump to content
  • entries
    940
  • comments
    5,894
  • views
    863,975

Writing the Treeview Widget


Josh

1,314 views

 Share

I've begun a Lua script for a Treeview widget. This is arguably one of the most complex widgets to implement, but after having done this in another language I have a design that I think is pretty simple. The script sorts all tree view nodes into a linear list-like table so that they can be drawn quickly. Like other widgets, the script will calculate where the starting point in the list is to display just the visible nodes. This is very important because it prevents the program from slowing down when the number of nodes gets really high and goes beyond the bounds of the scrollable area.

 

Script.itemheight = 18
Script.itemindent = 20

function Script:Start()
self.color = {}
self.color.background = Vec4(0.2,0.2,0.2,1)
self.color.foreground = Vec4(0.7,0.7,0.7,1)
self.color.border = Vec4(0,0,0,1)
end

function Script:Draw()
local gui = self.widget:GetGUI()
local pos = self.widget:GetPosition(true)
local sz = self.widget:GetSize(true)
local scale = self.widget:GetGUI():GetScale()
local style = self.widget:GetStyle()

--Update table of visible nodes
if self.visiblenodes==nil then
	self:UpdateNodes(self.widget)
end

--Draw background
gui:SetColor(self.color.background.r,self.color.background.g,self.color.background.b,self.color.background.a)
gui:DrawRect(pos.x,pos.y,sz.width,sz.height)

--Draw nodes
local n
for n=1,#self.visiblenodes do
	gui:SetColor(self.color.foreground.r,self.color.foreground.g,self.color.foreground.b,self.color.foreground.a)
	gui:DrawText(self.visiblenodes[n].widget:GetText(),pos.x + 2*scale + self.visiblenodes[n].indent,pos.y + 2*scale + self.itemheight*(n-1),100,20)
end

--Draw border
gui:SetColor(self.color.border.r,self.color.border.g,self.color.border.b,self.color.border.a)
gui:DrawRect(pos.x,pos.y,sz.width,sz.height,1)
end

--Place nodes into a linear list
function Script:UpdateNodes(node,indent)
if indent==nil then indent=0 end

if self.visiblenodes==nil then
	self.visiblenodes = {}
end

local n
local count = node:CountChildren()
local subnode
local gui = self.widget:GetGUI()

if node:Collapsed()==false then
	for n=0,count-1 do
		subnode = node:GetChild(n)
		self.visiblenodes[#self.visiblenodes+1] = {}
		self.visiblenodes[#self.visiblenodes].widget = subnode
		self.visiblenodes[#self.visiblenodes].indent = indent
		self:UpdateNodes(subnode,indent+self.itemindent)
	end
end
end

 

The linear list also allows you to instantly calculate the node under a mouse coordinate, so you can figure out which node was clicked without iterating through hundreds of nodes. It's very similar to the design of the listview widget, but with the added complexity of a hierarchy that can be expanded and collapsed.

 

blogentry-1-0-96542200-1472747604_thumb.jpg

  • Upvote 9
 Share

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...