Writing the Treeview Widget
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.
- 9
0 Comments
Recommended Comments
There are no comments to display.