DropDown = class(Turbine.UI.Control);
-- Adapted from Galuhad's DropDown class
-- http://www.lotrointerface.com/list.php?skinnerid=3762
-- Added member functions:
-- SetOpensUpward()
-- SetFont()
-- SetBorderColor()
-- SetInteriorColor()
-- SetExpanded()
-- SetSelectedItem()
-- GetSelectedItem()
-- Changes:
-- Replaced SetMaxItems() with
-- SetExpandedWidth(), SetExpandedHeight(), SetExpandedSize(), Get...()
-- Added events:
-- SelectionChanged
-- Added features:
-- The itemList can be text strings or controls. If strings, controls
-- to contain them will be created automatically.
-- The user can resize the expanded window by dragging the corner.
function DropDown:Constructor(itemList, selectedItem)
Turbine.UI.Control.Constructor(self);
if (type(itemList) ~= "table") then
error("itemList must be a table", 3);
end
if (selectedItem == nil) then
error("selectedItem is nil", 3);
end
self.itemList = itemList;
self.selectedItem = selectedItem;
self.callbacks = {};
-- Defaults for configurable options
self.borderColor = Turbine.UI.Color(1, 0.63, 0.63, 0.63);
self.borderSize = 2;
self.backColor = Turbine.UI.Color.Black;
self.expandedBackColor = Turbine.UI.Color(0.9, 0, 0, 0);
self.foreColor = Turbine.UI.Color(1, 0.90, 0.82, 0.53);
self.outlineColor = Turbine.UI.Color.Black;
self.selectedColor = Turbine.UI.Color.Yellow;
self.mouseOverColor = Turbine.UI.Color.White;
self.mouseOverOutlineColor = Turbine.UI.Color(1, 0.85, 0.65, 0);
self.alignment = Turbine.UI.ContentAlignment.MiddleCenter;
self.font = Turbine.UI.Lotro.Font.TrajanPro14;
self:SetBackColor(self.borderColor);
local interior = Turbine.UI.Control();
interior:SetParent(self);
interior:SetPosition(self.borderSize, self.borderSize);
interior:SetBackColor(self.backColor);
interior:SetMouseVisible(false);
self.interior = interior;
local arrow = Turbine.UI.Control();
arrow:SetParent(interior);
arrow:SetSize(14, 14);
arrow:SetBackground(0x41007E18);
arrow:SetBlendMode(Turbine.UI.BlendMode.Overlay);
arrow:SetMouseVisible(false);
self.arrow = arrow;
self:SetSelectedItem(selectedItem);
self:SetSize(100, 19);
end
function DropDown:SetBorderColor(color)
self.borderColor = color;
self:SetBackColor(color);
if (self.listWindow) then
self.listWindow:SetBackColor(color);
end
end
function DropDown:SetInteriorColor(color)
self.backColor = color;
self.interior:SetBackColor(color);
self.expandedBackColor = color;
if (self.listWindow) then
self.listWindow.interior:SetBackColor(color);
end
end
function DropDown:SetWidth(width)
self:SetSize(width, self:GetHeight());
end
function DropDown:SetHeight(height)
self:SetSize(self:GetWidth(), height);
end
function DropDown:SetSize(width, height)
Turbine.UI.Control.SetSize(self, width, height);
local interiorWidth = width - (2 * self.borderSize);
self.textHeight = height - (2 * self.borderSize);
self.interior:SetSize(interiorWidth, self.textHeight);
local arrowWidth, arrowHeight = self.arrow:GetSize();
local labelWidth = interiorWidth - 4;
self.label:SetSize(labelWidth, self.textHeight);
self.arrow:SetLeft(interiorWidth - arrowWidth);
self.arrow:SetTop(math.floor((self.textHeight - arrowHeight) / 2) - 1);
end
function DropDown:MouseEnter()
self.arrow:SetBackground(0x41007E1B);
end
function DropDown:MouseLeave()
self.arrow:SetBackground(0x41007E18);
end
function DropDown:MouseClick(args)
if (args.Button == Turbine.UI.MouseButton.Left) then
self:SetExpanded(not self.expanded);
end
end
function DropDown:SetParent(parent)
Turbine.UI.Control.SetParent(self, parent);
self:SetExpanded(false);
-- Find out which window this control is contained by
self.window = nil;
while (parent ~= nil) do
self.window = parent;
parent = parent:GetParent();
end
end
function DropDown:SetExpanded(expand)
if (self.listWindow) then
-- Remove previous event handlers on user controls
for _, cbInfo in ipairs(self.callbacks) do
local control, event, func = unpack(cbInfo);
RemoveCallback(control, event, func);
end
self.callbacks = {};
self.listWindow:Close();
end
if (expand) then
local window = Turbine.UI.Window();
local width = self:GetExpandedWidth();
window:SetZOrder(self.window:GetZOrder() + 1);
window:SetWidth(width);
window:SetBackColor(self.borderColor);
window:SetVisible(true);
local left, top = self:PointToScreen(0, self.borderSize + self.textHeight);
window:SetPosition(left, top);
window.Deactivated = function()
self:SetExpanded(false);
end
self.listWindow = window;
local interior = Turbine.UI.Control();
width = width - 2 * self.borderSize;
interior:SetWidth(width);
interior:SetParent(window);
interior:SetBackColor(self.expandedBackColor);
interior:SetPosition(self.borderSize, self.borderSize);
window.interior = interior;
local listBox = Turbine.UI.ListBox();
width = width - 14;
listBox:SetParent(interior);
listBox:SetWidth(width);
listBox:SetLeft(2);
self.listBox = listBox;
local scrollBar = Turbine.UI.Lotro.ScrollBar();
scrollBar:SetPosition(width + 3, 0);
scrollBar:SetWidth(10);
scrollBar:SetParent(interior);
scrollBar:SetOrientation(Turbine.UI.Orientation.Vertical);
listBox:SetVerticalScrollBar(scrollBar);
local height = 0;
for n, item in ipairs(self.itemList) do
local control = self:_CreateItem(listBox, n, item);
control:SetWidth(width);
listBox:AddItem(control);
height = height + control:GetHeight();
end
height = math.max(height, 3 * self.textHeight);
height = math.min(height, self:GetExpandedHeight() - (self.borderSize * 2));
interior:SetHeight(height);
listBox:SetHeight(height);
scrollBar:SetHeight(height - 16);
height = height + 2 * self.borderSize;
window:SetHeight(height);
-- If the expanded list goes off the right edge of the screeen, shift it to the left
local screenWidth, screenHeight = Turbine.UI.Display:GetSize()
width = self:GetExpandedWidth();
if (left + width > screenWidth) then
window:SetLeft(screenWidth - width);
end
-- If the expanded list goes off the bottom edge of the screen, move it above
if (top + height > screenHeight) then
window:SetTop(top - height - self.textHeight);
end
-- Allow it to be resized by dragging the corner
local resizer = Thurallor.UI.Resizer(interior);
resizer:SetMinimumSize(self:GetWidth() - (self.borderSize * 2), 3 * self.textHeight);
interior.Resizing = function()
local width, height = interior:GetSize();
listBox:SetSize(width - 14, height);
scrollBar:SetLeft(width - 11);
scrollBar:SetHeight(height - 16);
self.listBox:SetWidth(width - 14);
for n = 1, self.listBox:GetItemCount() do
self.listBox:GetItem(n):SetWidth(width);
end
width = width + 2 * self.borderSize;
height = height + 2 * self.borderSize;
window:SetSize(width, height);
self.expandedWidth = width;
self.expandedHeight = height;
end
window:Activate();
end
self.expanded = expand;
end
function DropDown:_CreateItem(listBox, n, item)
local control = item;
if (type(item) == "string") then
control = Turbine.UI.Label();
control.item = item;
control:SetHeight(self.textHeight);
control:SetFont(self.font);
if (item == self.selectedItem) then
control:SetForeColor(self.selectedColor);
else
control:SetForeColor(self.foreColor);
end
control:SetTextAlignment(self.alignment);
control:SetText(item);
control:SetMultiline(false);
control.MouseEnter = function()
control.foreColor = control:GetForeColor();
control:SetForeColor(self.mouseOverColor);
control:SetOutlineColor(self.mouseOverOutlineColor);
control:SetFontStyle(Turbine.UI.FontStyle.Outline);
end
control.MouseLeave = function()
control:SetForeColor(control.foreColor);
control:SetFontStyle(Turbine.UI.FontStyle.None);
end
end
if (listBox) then
local function MouseClick(ctl, args)
if (args.Button == Turbine.UI.MouseButton.Left) then
self:SetSelectedItem(item);
-- For backward compatibility with Galuhad's class:
DoCallbacks(self, "ItemChanged", { Index = n; Text = item });
end
end
-- Keep track of this so we can remove it when the pulldown closes
table.insert(self.callbacks, { control, "MouseClick", MouseClick });
AddCallback(control, "MouseClick", MouseClick);
end
return control;
end
function DropDown:GetSelectedItem()
return self.selectedItem;
end
function DropDown:GetText()
return self:GetSelectedItem()
end
function DropDown:SetSelectedItem(item)
self:SetExpanded(false);
self.selectedItem = item;
-- Delete old label (if any)
if (self.label) then
RemoveCallback(self.label, "MouseClick", self.labelMouseClick);
self.label:SetParent(nil);
end
-- Create or place new label
local label = self:_CreateItem(nil, 0, item);
label:SetParent(self.interior);
label:SetLeft(2);
self.labelMouseClick = function(_, args)
DoCallbacks(self, "MouseClick", args);
end
AddCallback(label, "MouseClick", self.labelMouseClick);
self.label = label;
self:SetSize(self:GetSize());
-- Make sure arrow control is in front
-- self.arrow:SetParent(nil);
-- self.arrow:SetParent(self.interior);
-- self.arrow:SetZOrder(3);
DoCallbacks(self, "SelectionChanged", { Item = item });
end
function DropDown:SetText(text)
self:SetSelectedItem(text);
end
function DropDown:SetAlignment(alignment)
self.alignment = alignment;
self:SetSelectedItem(self:GetSelectedItem());
end
function DropDown:SetFont(font)
self:SetExpanded(false);
self.font = font;
self.label:SetFont(font);
self.label:SetText(self.label:GetText());
end
function DropDown:GetExpandedWidth()
return self.expandedWidth or self:GetWidth();
end
function DropDown:GetExpandedHeight()
local defaultHeight = (self.textHeight * 8) + (self.borderSize * 2);
return self.expandedHeight or defaultHeight;
end
function DropDown:GetExpandedSize()
return self:GetExpandedWidth(), self:GetExpandedHeight();
end
function DropDown:SetExpandedWidth(width)
self:SetExpandedSize(width, self:GetExpandedHeight());
end
function DropDown:SetExpandedHeight(height)
self:SetExpandedSize(self:GetExpandedWidth(), height);
end
function DropDown:SetExpandedSize(width, height)
self:SetExpanded(false);
self.expandedWidth = width;
self.expandedHeight = height;
end
Thurallor = Thurallor or {};
Thurallor.UI = Thurallor.UI or {};
Thurallor.UI.DropDown = DropDown;