Slot = class(Turbine.UI.Control);
function Slot:Constructor(info, wantsMouseWheelEvents)
Turbine.UI.Control.Constructor(self);
self:SetMouseVisible(false);
self:SetSize(36, 36);
self.advanceFunc = {};
self:SetInfo(info);
self:SetBlendMode(Turbine.UI.BlendMode.AlphaBlend);
Turbine.UI.Control.SetAllowDrop(self, false);
self.wantsMouseWheelEvents = wantsMouseWheelEvents;
end
function Slot:GetInfo()
return self.info;
end
-- Get skill name(s) from moebius92's SkillData database
function Slot:GetSkillNames()
if (not self.skillNames and (self.info.type == Turbine.UI.Lotro.ShortcutType.Skill)) then
local shortcut = self.object and self.object.GetShortcut and self.object:GetShortcut();
self.skillNames = shortcut and shortcut:GetSkillName();
if (type(self.skillNames) == "string") then
self.skillNames = { self.skillNames };
end
end
return self.skillNames;
end
-- Get canonical skill name (with no fire oil, light oil, alternate stance, etc.)
function Slot:GetSkillName()
local skillNames = self:GetSkillNames();
if (skillNames) then
return skillNames[1];
end
end
function Slot:GetSkill()
local names = self:GetSkillNames();
if (type(names) == "string") then
return Thurallor.Utils.Watcher.GetSkillByNames(names);
elseif (type(names) == "table") then
return Thurallor.Utils.Watcher.GetSkillByNames(names);
end
end
function Slot:GetItem()
if (self.object.GetItem) then
return self.object:GetItem();
end
end
function Slot:GetItemName()
local item = self:GetItem();
return item and item:GetItemInfo():GetName();
end
function Slot:GetNumLabel()
return self.slotNumber;
end
function Slot:IsQuickslot()
return self.isQuickslot;
end
function Slot:SetActionEnabled(enabled)
self.actionEnabled = enabled;
if (self.object) then
self.object:SetMouseVisible(enabled);
end
if (self.numLabel) then
self.numLabel:SetMouseVisible(not enabled);
end
end
function Slot:SetAllowDrop(allowDrop)
if (self.numLabel) then
self.numLabel:SetAllowDrop(allowDrop);
elseif (self.object) then
self.object:SetAllowDrop(allowDrop);
end
end
function Slot:SetUseOnRightClick(useOnRightClick)
self.useOnRightClick = useOnRightClick;
if (self.object and self.object.SetUseOnRightClick) then
self.object:SetUseOnRightClick(useOnRightClick);
end
end
function Slot:SetDraggable(draggable)
if (draggable) then
self.numLabel.MouseDown = function(sender, args)
self:MouseDown(args);
end
self.numLabel.MouseUp = function(sender, args)
self:MouseUp(args);
end
self.numLabel.MouseMove = function()
self:MouseMove();
end
elseif (self.numLabel) then
self.numLabel.MouseDown = nil;
self.numLabel.MouseUp = nil;
self.numLabel.MouseMove = nil;
end
end
function Slot:SetInfo(info)
-- Discard old object, if it's a different type
if (self.object and (self.info.class ~= info.class)) then
self.object:SetParent(nil);
self.object = nil;
end
self.info = {};
DeepTableCopy(info, self.info);
if (not self.parent) then
return;
end
-- Create the quickslot object or command icon
if ((not info.class) or (info.class == "Turbine.UI.Lotro.Quickslot")) then
if (not self.object) then
local object = Turbine.UI.Lotro.Quickslot();
object:SetParent(self);
object:SetZOrder(1);
self.object = object;
-- Forward events to parent object
object.MouseClick = function(sender, args)
DoCallbacks(self, "MouseClick", args);
end
object.MouseWheel = function(sender, args)
DoCallbacks(self, "MouseWheel", args);
end
end
local shortcut = Turbine.UI.Lotro.Shortcut(info.type, ((type(info.Data) == "string") and info.Data:toWindows()) or info.Data);
self.object:SetShortcut(shortcut);
self.isQuickslot = true;
self.skillNames = nil;
self.object.DragDrop = function(sender)
sender:SetShortcut(Turbine.UI.Lotro.Shortcut(self.info.type, self.info.Data));
end
elseif ((info.class == "Turbine.UI.Control") or (info.class == "Turbine.UI.Lotro.EntityControl")) then
if (not self.object) then
local object;
if (info.type == "SelectTarget") then
object = Turbine.UI.Lotro.EntityControl();
object:SetSelectionEnabled(true);
object:SetContextMenuEnabled(false);
object:SetBackground(resources.Icon.SelectTarget);
self.watcher = Thurallor.Utils.Watcher;
self.player = Turbine.Gameplay.LocalPlayer:GetInstance();
self.getTargetFunc = loadstring(info.getTargetFunc);
else
-- MouseWheel events aren't implemented for Controls, only ListBoxes.
-- But I think they probably use more resources than Controls, so I'll
-- only use ListBoxes if the mouse wheel option is enabled.
if (self.wantsMouseWheelEvents) then
object = Turbine.UI.ListBox();
else
object = Turbine.UI.Control();
end
end
object:SetParent(self);
object:SetSize(32, 32);
object:SetPosition(3, 3);
object:SetZOrder(1);
self.object = object;
object.slot = self;
-- Forward events to parent object
object.MouseClick = function(obj, args)
if (obj.slot.info.type == "SelectTarget") then
-- Update the round-robin "cursor" to the next member, regardless
-- of whether the member was successfully selected; clicking on the
-- slot is enough to know the user's intent.
Thurallor.Utils.Watcher.GetNextPartyMember(obj.slot.entity);
end
DoCallbacks(obj.slot, "MouseClick", args);
end
object.MouseEnter = function(obj)
if (obj.slot.info.type == "SelectTarget") then
obj.slot:UpdateEntity();
obj.slot:SetWantsUpdates(true);
end
DoCallbacks(obj.slot, "MouseEnter");
end
object.MouseLeave = function(obj)
if (obj.slot.info.type == "SelectTarget") then
obj:SetBackground(resources.Icon.SelectTarget);
obj:SetEntity(nil);
obj.slot.entity = nil;
obj.slot:SetWantsUpdates(false);
end
DoCallbacks(obj.slot, "MouseLeave");
end
object.MouseWheel = function(obj, args)
DoCallbacks(obj.slot, "MouseWheel", args);
end
-- Add tooltip
if (info.type == "SelectTarget") then
self:SetTooltip(function()
local entity = self.object:GetEntity();
return entity and entity:GetName() or L:GetText("/SequenceEditor/NoTarget");
end);
end
end
self.isQuickslot = false;
end
self:SetUseOnRightClick(self.useOnRightClick);
-- Draw text overlay and icon overlay (if any)
if (not self.textOverlay) then
local textOverlay = Turbine.UI.Label();
textOverlay:SetParent(self);
textOverlay:SetZOrder(2);
textOverlay:SetSize(32, 32);
textOverlay:SetPosition(3, 3);
textOverlay:SetMouseVisible(false);
textOverlay:SetFont(Turbine.UI.Lotro.Font.Verdana10);
textOverlay:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleCenter);
textOverlay:SetFontStyle(Turbine.UI.FontStyle.Outline);
textOverlay:SetOutlineColor(Turbine.UI.Color(1, 0, 0, 0));
textOverlay:SetMultiline(true);
textOverlay:SetMarkupEnabled(true);
textOverlay:SetBlendMode(Turbine.UI.BlendMode.AlphaBlend);
self.textOverlay = textOverlay;
end
self.background = info.background;
if (info.altIcon) then
self.background = info.altIcon;
end
self.textOverlay:SetBackground(self.background);
self.textOverlay:SetText(info.textOverlay);
end
-- For "Select Target" slots only:
function Slot:UpdateEntity()
local entity = self.getTargetFunc(Thurallor.Utils.Watcher, self.player, self.info.raidMemberName, self.info.number);
if (entity ~= self.entity) then
self.object:SetEntity(entity);
self.entity = entity;
self.tooltip:Update();
end
if (entity) then
self.object:SetBackground(resources.Icon.SelectTargetKnown);
else
self.object:SetBackground(resources.Icon.SelectTargetUnknown);
end
end
function Slot:SetTooltip(content)
if (self.tooltip) then
self.tooltip:SetVisible(false);
self.tooltip:Detach();
end
self.tooltip = Thurallor.UI.Tooltip(content);
self.tooltip:Attach(self.object);
end
function Slot:SetNumLabel(slotNumber)
if (not self.numLabel) then
local numLabel = Turbine.UI.Label();
numLabel:SetParent(self);
numLabel:SetFont(Turbine.UI.Lotro.Font.TrajanPro15);
numLabel:SetFontStyle(Turbine.UI.FontStyle.Outline);
numLabel:SetOutlineColor(Turbine.UI.Color(1, 0, 0, 0));
numLabel:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleCenter);
numLabel:SetBlendMode(Turbine.UI.BlendMode.AlphaBlend);
numLabel:SetSize(38, 38);
numLabel:SetZOrder(3);
numLabel.DragDrop = function(sender, args)
DoCallbacks(self, "DragDrop", args);
end
numLabel.MouseClick = function(sender, args)
DoCallbacks(self, "MouseClick", args);
end
self.numLabel = numLabel;
end
self.numLabel:SetText(slotNumber);
self.slotNumber = slotNumber;
end
function Slot:StartCooldown(period)
if (period <= 0) then
period = 0.001;
end
self.coolDown = period;
self.resetTime = Turbine.Engine.GetGameTime() + period;
if (self.textOverlay) then
self.textOverlay:SetBackground(resources.Icon.Delay);
self.textOverlay:SetText(nil);
end
self:ShowTimeRemaining(true);
self:SetWantsUpdates(true);
end
function Slot:Update()
if (self.info.type == "SelectTarget") then
self:UpdateEntity();
else
self:ShowTimeRemaining();
end
end
-- Reuse the numLabel layer for cooldown overlay.
function Slot:ShowTimeRemaining(starting)
local currentTime = Turbine.Engine.GetGameTime();
-- Check for abort ("Reset" event handler removed)
if (not starting and not self.Reset) then
self.resetTime = currentTime;
end
if (currentTime >= self.resetTime) then
self.numLabel:SetParent(nil);
self.numLabel = nil;
self.resetTime = nil;
self:SetWantsUpdates(false);
if (self.textOverlay) then
self.textOverlay:SetBackground(self.background);
self.textOverlay:SetText(self.info.textOverlay);
end
self.hidden = self.hiddenAfterReset;
DoCallbacks(self, "Reset");
else
self:SetNumLabel("");
self.numLabel.MouseClick = nil;
self.numLabel:SetPosition(3, 3);
self.numLabel:SetSize(32, 32);
local steps = resources.Icon.CoolDownEnd - resources.Icon.CoolDownStart + 1;
local progress = 1 - (self.resetTime - currentTime) / self.coolDown;
self.numLabel:SetBackground(resources.Icon.CoolDownStart + math.floor(progress * steps));
end
end
function Slot:SetSelected(selected, color)
if (not selected) then
if (self.marquee) then
self.marquee:SetParent(nil);
self.marquee = nil;
end
return;
end
if (not color) then
color = Turbine.UI.Color.White;
end
if (not self.marquee) then
local marquee = Thurallor.UI.Marquee();
marquee:SetParent(self);
marquee:SetPosition(2, 2);
marquee:SetSize(34, 34);
marquee:SetMouseVisible(false);
self.marquee = marquee;
end
self.marquee:SetColor(color);
end
function Slot:SetParent(parent)
self.parent = parent;
if (parent) then
self:SetInfo(self.info);
elseif (self.object) then
self:MouseLeave();
self.object:SetParent(nil);
self.object = nil;
end
Turbine.UI.Control.SetParent(self, parent);
end
function Slot:DragDrop(args)
local info = {};
info.class = "Turbine.UI.Lotro.Quickslot";
local newShortcut = args.DragDropInfo:GetShortcut();
if (newShortcut) then
info.type = newShortcut:GetType();
info.Data = newShortcut:GetData();
self:SetInfo(info);
DoCallbacks(self, "ShortcutChanged", info.type, info.Data);
end
-- Don't remove the item/skill from the location where it was dragged from.
args.DragDropInfo:SetSuccessful(false);
end
function Slot:MouseEnter()
if ((self.actionEnabled) and (not self.highlight)) then
local highlight = Turbine.UI.Control();
highlight:SetParent(self);
highlight:SetSize(32, 32);
highlight:SetPosition(3, 3);
highlight:SetZOrder(4);
highlight:SetBlendMode(Turbine.UI.BlendMode.Overlay);
highlight:SetBackground(resources.Icon.Highlight);
highlight:SetMouseVisible(false);
self.highlight = highlight;
end
end
function Slot:MouseLeave()
if (self.highlight) then
self.highlight:SetParent(nil);
self.highlight = nil;
end
end
function Slot:MouseDown(args)
if (args.Button == Turbine.UI.MouseButton.Left) then
-- Drag begin. Save the current position of the slot and mouse.
self.mouseDown = true;
self.mouseMoved = false;
self.originalLeft, self.originalTop = self:PointToScreen(0, 0);
self.originalMouseX, self.originalMouseY = Turbine.UI.Display.GetMouseX(), Turbine.UI.Display.GetMouseY();
end
end
function Slot:MouseMove()
if (not self.mouseDown) then
return;
end
-- Detach from parent if we haven't already done so.
if (not self.mouseMoved) then
self.numLabel:SetText(nil);
self.parent = self:GetParent();
self.tempContainer = Turbine.UI.Window();
self.tempContainer:SetVisible(true);
self.tempContainer:SetSize(self:GetSize());
self.tempContainer:SetZOrder(2147483647);
self.tempContainer:SetOpacity(0.75);
self:SetParent(self.tempContainer);
self:SetPosition(0, 0);
self.mouseMoved = true;
end
-- Drag continuing. Find out how much the mouse has moved.
local newMouseX, newMouseY = Turbine.UI.Display.GetMouseX(), Turbine.UI.Display.GetMouseY();
local deltaX, deltaY = newMouseX - self.originalMouseX, newMouseY - self.originalMouseY;
-- Move the icon and overlay.
local left, top = self.originalLeft + deltaX, self.originalTop + deltaY;
self.tempContainer:SetPosition(left, top);
-- Show a red "X" if invalid drag location is selected.
local centerX, centerY = left + 16, top + 16;
if (self:DropPositionValid(centerX, centerY)) then
self.numLabel:SetBackground(nil);
else
self.numLabel:SetBackground(resources.Icon.DragFail);
end
end
function Slot:MouseUp(args)
if (args.Button ~= Turbine.UI.MouseButton.Left) then
return;
end
self.mouseDown = false;
if (not self.mouseMoved) then
return;
end
-- Reattach to parent.
local left, top = self.tempContainer:GetPosition();
self:SetParent(self.parent);
self.tempContainer:Close();
self.tempContainer = nil;
self.numLabel:SetBackground(nil);
self.numLabel:SetText(self.slotNumber);
local centerX, centerY = left + 16, top + 16;
self:DragDropComplete(centerX, centerY);
end
-- Event handlers that should be overridden
--
-- function Slot:ShortcutChanged(shortcutType, shortcutData)
-- Puts("ShortcutChanged(" .. Serialize(shortcutType) .. ", " .. Serialize(shortcutData) .. ")");
-- end
--
-- function Slot:MouseClick(args)
-- Puts("MouseClick(" .. Serialize(args) .. ")");
-- end
--
-- function Slot:MouseWheel(args)
-- Puts("MouseWheel(" .. Serialize(args) .. ")");
-- end
--
-- function Slot:DropPositionValid(left, top)
-- Puts("DropPositionValid(" .. tostring(left) .. ", " .. tostring(top) .. ")");
-- return true;
-- end
--
-- function Slot:DragDropComplete(left, top)
-- Puts("DragDropComplete(" .. tostring(left) .. ", " .. tostring(top) .. ")");
-- return true;
-- end