TreeControl = class(Turbine.UI.Control);
iconWidth = 20;
function TreeControl:Constructor()
Turbine.UI.Control.Constructor(self);
self.width = self:GetWidth();
self.expanded = false;
self.enabled = true;
self.children = {};
self.childIcons = {};
self.lineHeight = 0;
self.childrenHeight = 0;
self.columns = {};
self.weights = {};
self.childContainer = Turbine.UI.Control();
self.childContainer:SetLeft(iconWidth);
self.icon = TreeIcon(3);
self.icon.Click = function()
self:IconClick();
end
self:AddColumn(self.icon, 0);
AddCallback(self.childContainer, "SizeChanged", function(sender) self:ChildContainerSizeChanged() end);
end
function TreeControl:IconClick()
if (self.enabled) then
self:SetExpanded(not self.expanded);
DoCallbacks(self, "IconClicked", self.expanded);
end
end
function TreeControl:SetExpanded(expanded)
if (expanded) then
self.childContainer:SetParent(self);
Turbine.UI.Control.SetHeight(self, self.lineHeight + self.childrenHeight);
else
self.childContainer:SetParent(nil);
Turbine.UI.Control.SetHeight(self, self.lineHeight);
end
if (#self.children > 0) then
if (expanded) then
self.icon:SetMode(2, self.parentTreeControl);
else
self.icon:SetMode(1, self.parentTreeControl);
end
else
self.icon:SetMode(3);
end
if ((self.expanded ~= expanded) and (self.ExpandedChanged)) then
self:ExpandedChanged();
end
self.expanded = expanded;
end
function TreeControl:ChildContainerSizeChanged()
for c = 1, #self.children do
self.childIcons[c]:SetTop(self.lineHeight + self.children[c]:GetTop());
self.childIcons[c]:SetHeight(self.children[c]:GetHeight());
end
self:SetExpanded(self.expanded);
end
function TreeControl:AddColumn(control, weight)
if (not control) then
control = Turbine.UI.Control();
control:SetSize(1, 1);
end
table.insert(self.columns, control);
table.insert(self.weights, weight);
control:SetParent(self);
local height = control:GetHeight();
if (height > self.lineHeight) then
self:SetLineHeight(height);
end
self:DistributeColumns();
end
function TreeControl:DistributeColumns()
-- Calculate total weight, total width of weighted columns, and total number of weighted columns.
local weightedColumns = #self.columns;
local weightedWidth = self.width;
local totalWeight = 0;
for col = 1, #self.columns do
local weight = self.weights[col];
totalWeight = totalWeight + weight;
if (weight == 0) then
weightedColumns = weightedColumns - 1;
weightedWidth = weightedWidth - self.columns[col]:GetWidth();
end
end
-- Apply widths in proportion to column weights.
local remainingWeightedWidth = weightedWidth;
for col = 1, #self.columns do
local weight = self.weights[col];
if (weight > 0) then
if (weightedColumns == 1) then
width = remainingWeightedWidth;
else
width = (weight / totalWeight) * weightedWidth;
width = math.floor(width + 0.5);
end
self:SetColumnWidth(col, width);
weightedColumns = weightedColumns - 1;
remainingWeightedWidth = remainingWeightedWidth - width;
end
end
-- Set position of each column.
local left = 0;
for col = 1, #self.columns do
self:SetColumnLeft(col, left);
left = left + self.columns[col]:GetWidth();
end
end
function TreeControl:SetColumnLeft(col, left)
self.columns[col]:SetLeft(left);
if (col > 2) then
left = left - iconWidth;
for c = 1, #self.children do
self.children[c]:SetColumnLeft(col, left);
end
end
end
function TreeControl:SetColumnWidth(col, width)
self.columns[col]:SetVisible(width ~= 0);
if (width > 0) then
self.columns[col]:SetWidth(width);
end
if (col > 1) then
for c = 1, #self.children do
self.children[c]:SetColumnWidth(col, width);
end
end
end
function TreeControl:SetLineHeight(height)
for col = 1, #self.columns do
self.columns[col]:SetHeight(height);
end
self.lineHeight = height;
self.childContainer:SetTop(height);
self:SetExpanded(self.expanded); -- adjust self height
end
function TreeControl:SetColumnWeight(col, weight)
self.weights[col] = weight;
self:DistributeColumns();
end
function TreeControl:SetWidth(width)
self.width = width;
Turbine.UI.Control.SetWidth(self, width);
self.childContainer:SetWidth(width);
width = width - iconWidth;
for c = 1, #self.children do
self.children[c]:SetWidth(width);
end
self:DistributeColumns();
end
function TreeControl:SetSize(width, height)
self:SetWidth(width);
end
function TreeControl:SetHeight(height)
end
function TreeControl:GetChildren()
return self.children;
end
function TreeControl:GetColumns()
return self.columns;
end
function TreeControl:RemoveChild(child)
local foundChild;
for c = 1, #self.children do
if (child == self.children[c]) then
foundChild = c;
end
end
if (foundChild) then
child.icon.stemLeft:SetVisible(false);
child:SetParent(nil);
child.parentTreeControl = nil;
table.remove(self.children, foundChild);
self.childIcons[foundChild]:SetParent(nil);
table.remove(self.childIcons, foundChild);
if ((foundChild > #self.children) and (#self.children > 0)) then
self.childIcons[#self.children]:SetMode(5);
end
self:ChildExpandedChanged();
else
error("Child not found!", 2);
end
return foundChild;
end
function TreeControl:InsertChild(child, c)
local icon = TreeIcon(5);
icon:SetParent(self);
if (c > #self.children) then
if (#self.children > 0) then
self.childIcons[#self.children]:SetMode(4);
end
else
icon:SetMode(4);
end
child.parentTreeControl = self;
table.insert(self.children, c, child);
table.insert(self.childIcons, c, icon);
child:SetParent(self.childContainer);
child:SetLeft(0);
child:SetWidth(self.width - iconWidth);
AddCallback(child, "SizeChanged", function() self:ChildExpandedChanged() end);
self:ChildExpandedChanged();
end
function TreeControl:AddChild(child)
return self:InsertChild(child, #self.children + 1);
end
function TreeControl:ChildExpandedChanged()
self.childrenHeight = 0;
for c = 1, #self.children do
local child = self.children[c];
child:SetTop(self.childrenHeight);
self.childrenHeight = self.childrenHeight + child:GetHeight();
end
self.childContainer:SetHeight(self.childrenHeight);
end
function TreeControl:IsMouseInside()
local x, y = self:GetMousePosition();
local inside = ((x >= 0) and (x < self.width) and (y >= 0) and (y < self:GetHeight()));
if (not inside) then
return false, nil;
elseif (y < self.lineHeight) then
return true, self;
else
for c = 1, #self.children do
child = self.children[c];
local insideChild, childChild = child:IsMouseInside();
if (insideChild) then
return true, childChild;
end
end
-- We must be hovering over the stems.
return false, nil;
end
end
function TreeControl:GetParentTreeControl()
return self.parentTreeControl;
end