Bar = class(Node);
function Bar:Constructor(group, barID, settings)
Turbine.UI.Window.Constructor(self);
self.constructing = true;
self:SetZOrder(0);
self:SetMouseVisible(false);
self:SetAllowDrop(true);
self.slotContainer = Turbine.UI.Control();
self.slotContainer:SetParent(self);
self.slotContainer:SetMouseVisible(false);
self.parent = group;
self.manager = group.manager;
self.objectID = barID;
self.onLoad = onLoad;
self.slots = {};
self.visibleSlots = {};
self.cursorPos = 3;
self.cursorSlot = 1;
self.globals = self.manager.settings;
self.eventGeneratorIDs = {};
self.player = Turbine.Gameplay.LocalPlayer:GetInstance();
self.automaticClicks = 0;
-- Default settings
local defaults = {};
defaults.type = "bar";
defaults.locked = false;
defaults.hidden = false;
defaults.color = Thurallor.Utils.Color();
defaults.color:SetHSV(math.random(), 1, 1);
defaults.color = defaults.color:GetHex();
defaults.cursorStyle = "SmallSquareGlow";
defaults.caption = { };
defaults.caption.hidden = false;
defaults.caption.text = L:GetText("/Default/BarName");
defaults.caption.position = "beginning";
defaults.caption.width = 80;
defaults.caption.height = 35;
defaults.caption.font = Turbine.UI.Lotro.Font.TrajanPro15;
defaults.slotSize = 35; -- must be an even number
defaults.slotSpacing = 0;
defaults.orientation = "Right";
defaults.visibleSlots = 5;
defaults.cursorHomePosition = 2;
defaults.animation = { duration = 0.1 };
defaults.sequenceItemInfo = { {}, {}, {}, {}, {} };
defaults.position = { left = math.floor(Turbine.UI.Display:GetWidth() / 2); top = math.floor(Turbine.UI.Display:GetHeight() / 2 )};
defaults.anchor = "TopLeft";
defaults.eventHandlers = {};
defaults.eventsEnabled = false;
defaults.hideAutomatics = true;
defaults.hideInactiveBranches = true;
-- Previously-saved settings override the defaults
DeepTableCopy(settings, defaults);
DeepTableCopy(defaults, settings);
self.settings = settings;
self:ReapplySettings();
self.constructing = nil;
self:SetWantsEvents(self.settings.eventsEnabled);
end
function Bar:ReapplySettings()
-- Make color object from hex string
self.color = Thurallor.Utils.Color(1, 0, 0, 0);
self.color:SetHex(self.settings.color);
-- For backward compatibility
self.settings.cursorStyle = string.gsub(self.settings.cursorStyle, "SilverFrame(%d)", "MetalFrame%1");
for _, info in pairs(self.settings.sequenceItemInfo) do
if (info.action) then
info.action = string.gsub(info.action, "item.eventName", "item.info.eventName");
info.action = string.gsub(info.action, "item.bagSlot", "item.info.bagSlot");
end
if ((info.class == "Turbine.UI.Lotro.Quickslot") and (info.background)) then
info.altIcon = info.background;
info.background = nil;
end
end
for _, handler in pairs(self.settings.eventHandlers) do
if (handler.action) then
handler.action = string.gsub(handler.action, "self:SetHidden%(false%); self:BringToFront%(%); ", "self:SetHidden(false); ");
handler.action = string.gsub(handler.action, "self:SetHidden%(false%); self:Activate%(%); ", "self:SetHidden(false); ");
handler.action = string.gsub(handler.action, "self:Expand%(%); self:Activate%(%); ", "self:Expand(); ");
handler.action = string.gsub(handler.action, "self:Expand%(%); self:BringToFront%(%); ", "self:Expand(); ");
handler.action = string.gsub(handler.action, "self:MoveToMouseCursor%(%); self:Activate%(%); ", "self:MoveToMouseCursor%(%); ");
end
end
-- Derived from settings
self:SetCursorStyle(self.settings.cursorStyle);
self:GetQuickSlots();
self:FindHiddenSlots();
self:Redraw();
end
function Bar:Activate()
-- This used to be called in event handlers after Expand(), MoveToMouseCursor(), and SetHidden(false).
-- Don't want to use Turbine.UI.Window.Activate() because that would steal focus from the chat window.
end
-- Bring this bar in front of all other bars.
function Bar:BringToFront()
-- Don't want to use Turbine.UI.Window.Activate() because that would steal focus from the chat window.
self:SetZOrder(1);
self:SetZOrder(0);
end
function Bar:CanHaveChildren()
return false;
end
function Bar:Contains(object)
return false;
end
function Bar:SetColor(color)
Node.SetColor(self, color);
self:Redraw(true);
self:SetCursorStyle();
if (self.sequenceEditor) then
self.sequenceEditor:Redraw();
end
end
function Bar:SetName(caption)
Node.SetName(self, caption);
self:Redraw(true);
if (self.sequenceEditor) then
self.sequenceEditor:SetText(caption);
end
if (self.exportWindow) then
self.exportWindow:SetText(caption);
end
end
function Bar:SetCaptionSize(width, height)
Node.SetCaptionSize(self, width, height);
self:Redraw(true);
self:OffsetPosition(0, 0);
end
function Bar:SetCaptionFont(font)
self.settings.caption.font = font;
self:SaveSettings(false);
self:Redraw(true);
end
function Bar:SetCaptionHidden(hide)
self.settings.caption.hidden = hide;
self:SaveSettings(false);
self:Redraw(true);
end
function Bar:ApplyHiddenness()
local hidden = self:IsHidden();
if ((not hidden) and (not self:IsVisible())) then
self.visibleSlots = {};
end
self:SetCursorSlot(self.cursorSlot);
self:SetVisible(not hidden);
self:SaveSettings(true);
end
function Bar:Collapse()
if (self.settings.collapsed) then
return;
end
self.settings.collapsed = self.cursorPos;
self:Redraw(true);
local x1, y1 = self:GetSlotCoords(1);
if ((self.settings.orientation == "Up") or (self.settings.orientation == "Left")) then
x1, y1 = self:GetSlotCoords(self.settings.visibleSlots);
end
local x2, y2 = self:GetSlotCoords(self.settings.cursorHomePosition);
self:OffsetPosition(x2 - x1, y2 - y1);
self:SetCursorPos(1);
self:SetCursorSlot(self.cursorSlot);
self:SaveSettings(false);
end
function Bar:IsCollapsed()
return ((self.settings.visibleSlots == 1) or (self.settings.collapsed ~= nil));
end
function Bar:Expand()
if (not self.settings.collapsed) then
return;
end
local cursorPos = math.min(self.settings.collapsed, self.settings.visibleSlots);
self.settings.collapsed = nil;
self:Redraw(true);
local x1, y1 = self:GetSlotCoords(1);
if ((self.settings.orientation == "Up") or (self.settings.orientation == "Left")) then
x1, y1 = self:GetSlotCoords(self.settings.visibleSlots);
end
local x2, y2 = self:GetSlotCoords(self.settings.cursorHomePosition);
self:OffsetPosition(x1 - x2, y1 - y2);
self:SetCursorPos(cursorPos);
self:SetCursorSlot(self.cursorSlot);
self:SaveSettings(false);
end
function Bar:IsExpanded()
return ((self.settings.visibleSlots == 1) or (self.settings.collapsed == nil));
end
-- Updates the sequence item when a user drags a shortcut onto the sequence editor
function Bar:ShortcutChanged(i)
self:SaveSettings(false);
self:GetQuickSlots();
self:FindHiddenSlots();
self:Reset();
end
-- Initialize "hidden" and "folded" flags
function Bar:FindHiddenSlots()
for i = 1, #self.slots, 1 do
local slot = self.slots[i];
slot.folded = false;
if (self.settings.hideAutomatics and slot.info.automatic) then
slot.hidden = true;
else
slot.hidden = false;
end
end
end
function Bar:GetSequence()
return self.sequence;
end
-- Creates (or recreates) the array of objects (e.g. Quickslot) according to self.settings.sequenceItemInfo
function Bar:GetQuickSlots()
-- Hide and destroy existing clickable objects, if any
for s = 1, #self.slots, 1 do
self.slots[s]:SetParent(nil);
end
-- Unregister as event(s) generator. We will re-register for each generated event as we loop through the sequence below.
for eventName, generatorID in pairs(self.eventGeneratorIDs) do
self.manager:RemoveEventGenerator(generatorID, eventName);
end
self.sequence = Sequence(self, self.settings.sequenceItemInfo);
self.manager:SetIncludees(self.objectID, self.sequence:GetIncludes());
-- Register as generator of event(s)
self.eventGeneratorIDs = self.sequence:GetEvents();
for eventName in keys(self.eventGeneratorIDs) do
self.eventGeneratorIDs[eventName] = self.manager:AddEventGenerator(self, eventName);
end
-- Iterate through the sequence configuring the clickable objects.
self.slots = self.sequence:GetSlots(); -- returns array of Slot instances
for s = 1, #self.slots, 1 do
local slot = self.slots[s];
local info = slot.info;
self:ConfigureSlot(slot, s);
AddCallback(slot, "MouseClick", function(sender, args)
if (args.Button == Turbine.UI.MouseButton.Left) then
self:SlotClick(sender.s, false);
end
end);
end
-- Create a "reset" slot to be displayed when all other slots are folded
local info = { type = "Reset"; class = "Turbine.UI.Control"; background = resources.Icon.Reset };
self.resetSlot = Slot(info);
self:ConfigureSlot(self.resetSlot, #self.slots);
AddCallback(self.resetSlot, "MouseClick", function(sender, args)
if (args.Button == Turbine.UI.MouseButton.Left) then
self:Reset();
end
end);
end
function Bar:ConfigureSlot(slot, s)
slot:SetZOrder(2);
slot:SetActionEnabled(true);
slot:SetAllowDrop(false);
slot:SetDraggable(false);
slot.bar = self;
slot.s = s;
slot.MouseClick = nil; -- avoid multiple callbacks when the slot is reconfigured
slot.MouseEnter = nil;
AddCallback(slot, "MouseClick", function(sender, args)
-- Right-click displays the settings menu.
if (args.Button == Turbine.UI.MouseButton.Right) then
self:ShowSettingsMenu();
end
end);
AddCallback(slot, "MouseEnter", function(sender, args)
self:MouseArrive();
end);
end
function Bar:Redraw(noReset)
if (self.settings.collapsed) then
self.displaySlots = 1;
else
self.displaySlots = self.settings.visibleSlots;
end
local slotsLongDimension = (2 * self.cursorMargin) + (self.displaySlots + 1) * self.settings.slotSize + self.displaySlots * self.settings.slotSpacing;
local slotsShortDimension = (2 * self.cursorMargin) + self.settings.slotSize;
local captionMargin = 4;
local captionWidth, captionHeight = self.settings.caption.width, self.settings.caption.height;
local barWidth, barHeight, slotsWidth, slotsHeight, captionLeft, captionTop;
if ((self.settings.orientation == "Up") or (self.settings.orientation == "Down")) then
slotsWidth, slotsHeight = slotsShortDimension, slotsLongDimension;
-- Position slots and caption horizontally; set bar width
if (slotsWidth < captionWidth) then
barWidth = captionWidth;
self.slotsLeft = math.floor((barWidth - slotsWidth) / 2);
captionLeft = 0;
elseif (slotsWidth > captionWidth) then
barWidth = slotsWidth;
self.slotsLeft = 0;
captionLeft = math.floor((barWidth - captionWidth) / 2);
else -- (slotsWidth == captionWidth)
barWidth, self.slotsLeft, captionLeft = slotsWidth, 0, 0;
end
-- Position slots and caption vertically; set bar height
if (self.settings.orientation == "Up") then
if (self.settings.caption.position == "beginning") then
self.slotsTop = 0;
captionTop = slotsHeight - self.cursorMargin + captionMargin;
barHeight = math.max(slotsHeight, captionTop + captionHeight);
else -- (self.settings.caption.position == "end")
captionTop = math.max(0, self.cursorMargin + self.settings.slotSize - (captionHeight + captionMargin));
self.slotsTop = math.max((captionHeight + captionMargin) - (self.cursorMargin + self.settings.slotSize), 0);
barHeight = self.slotsTop + slotsHeight;
end
else -- (self.settings.orientation == "Down")
if (self.settings.caption.position == "beginning") then
captionTop = math.max(0, self.cursorMargin - (captionHeight + captionMargin));
self.slotsTop = math.max((captionHeight + captionMargin) - self.cursorMargin, 0);
barHeight = self.slotsTop + slotsHeight;
else -- (self.settings.caption.position == "end")
self.slotsTop = 0;
captionTop = slotsHeight - self.cursorMargin - self.settings.slotSize + captionMargin;
barHeight = math.max(slotsHeight, captionTop + captionHeight);
end
end
else -- ((self.settings.orientation == "Left") or (self.settings.orientation == "Right")) then
slotsWidth, slotsHeight = slotsLongDimension, slotsShortDimension;
-- Position slots and caption vertically; set bar height
if (slotsHeight < captionHeight) then
barHeight = captionHeight;
self.slotsTop = math.floor((barHeight - slotsHeight) / 2);
captionTop = 0;
elseif (slotsHeight > captionHeight) then
barHeight = slotsHeight;
self.slotsTop = 0;
captionTop = math.floor((barHeight - captionHeight) / 2);
else -- (slotsHeight == captionHeight)
barHeight, self.slotsTop, captionTop = slotsHeight, 0, 0;
end
-- Position slots and caption horizontally; set bar width
if (self.settings.orientation == "Left") then
if (self.settings.caption.position == "beginning") then
self.slotsLeft = 0;
captionLeft = slotsWidth - self.cursorMargin + captionMargin;
barWidth = math.max(slotsWidth, captionLeft + captionWidth);
else -- (self.settings.caption.position == "end")
captionLeft = math.max(0, self.cursorMargin + self.settings.slotSize - (captionWidth + captionMargin));
self.slotsLeft = math.max((captionLeft + captionWidth + captionMargin) - (self.cursorMargin + self.settings.slotSize), 0);
barWidth = self.slotsLeft + slotsWidth;
end
else -- (self.settings.orientation == "Right")
if (self.settings.caption.position == "beginning") then
captionLeft = math.max(0, self.cursorMargin - (captionWidth + captionMargin));
self.slotsLeft = math.max((captionWidth + captionMargin) - self.cursorMargin, 0);
barWidth = self.slotsLeft + slotsWidth;
else -- (self.settings.caption.position == "end")
self.slotsLeft = 0;
captionLeft = slotsWidth - self.cursorMargin - self.settings.slotSize + captionMargin;
barWidth = math.max(slotsWidth, captionLeft + captionWidth);
end
end
end
self.slotContainer:SetSize(slotsWidth, slotsHeight);
self.slotContainer:SetPosition(self.slotsLeft, self.slotsTop);
self:DrawCaption();
self.caption:SetSize(captionWidth, captionHeight);
self.caption:SetPosition(captionLeft, captionTop);
self:SetStretchMode(0);
self:SetSize(barWidth, barHeight);
self:SetStretchMode(1);
self:SetSize(barWidth * self.globals.uiScale / 32, barHeight * self.globals.uiScale / 32);
--self.slotContainer:SetBackColor(Turbine.UI.Color(0.20, 0, 1, 0));
--self.caption:SetBackColor(Turbine.UI.Color(0.20, 0, 0, 1));
--self:SetBackColor(Turbine.UI.Color(0.10, 1, 1, 1));
self:SetPosition();
self:SetOpacity(self.globals.uiOpacity);
-- Draw cursor icon and slots.
if (not noReset) then
self:Reset();
end
self:ApplyHiddenness();
end
function Bar:Reset()
self.sequence:UnfoldAllSlots();
self.animationStopped = false;
local cursorPos = self.settings.cursorHomePosition;
if (self.settings.collapsed) then
self.settings.collapsed = self.settings.cursorHomePosition;
cursorPos = 1;
end
self:SetCursorPos(cursorPos);
self.clickedPos = cursorPos;
self.clickedSlot = 1;
self:SetCursorSlot(1);
if (self.slots[1] and self.slots[1].info.automatic) then
self:SlotClick(1, true);
end
end
-- Moves the cursor to the specified position on the bar
function Bar:SetCursorPos(pos)
local resource = resources.Cursor[self.settings.cursorStyle];
local left, top = self:GetSlotCoords(pos);
left = left - self.cursorMargin + resource.xOffset;
top = top - self.cursorMargin + resource.yOffset;
self.cursor.left, self.cursor.top = left, top;
self.cursor:SetPosition(left, top);
self.cursorPos = pos;
end
function Bar:DrawCaption()
if (not self.caption) then
self.caption = Turbine.UI.Control();
self.caption:SetParent(self);
self.caption:SetZOrder(10);
self.caption:SetMouseVisible(true);
-- While mouse is over caption, highlight the label to indicate that it can be clicked.
function self.caption.MouseEnter(caption)
caption.label:SetFontStyle(Turbine.UI.FontStyle.None);
caption.label:SetOutlineColor(self.color); -- boldface effect
caption.label:SetFontStyle(Turbine.UI.FontStyle.Outline);
caption.label:SetVisible(true);
end
function self.caption.MouseLeave(caption)
caption.label:SetFontStyle(Turbine.UI.FontStyle.None);
caption.label:SetOutlineColor(Turbine.UI.Color(0.75, 0, 0, 0));
caption.label:SetFontStyle(Turbine.UI.FontStyle.Outline);
caption.label:SetVisible(not self.settings.caption.hidden);
end
function self.caption.MouseClick(caption, args)
if (self.mouseMoved) then
self.mouseMoved = false;
return;
end
-- Left-click resets the sequence back to the beginning.
if (args.Button == Turbine.UI.MouseButton.Left) then
self:Reset();
end
-- Right-click displays the settings menu.
if (args.Button == Turbine.UI.MouseButton.Right) then
self:ShowSettingsMenu();
end
end
function self.caption.MouseDoubleClick(caption, args)
-- Left-double-click opens the caption editor.
if (args.Button == Turbine.UI.MouseButton.Left) then
self:EditCaption();
end
-- Right-double-click would open the sequence editor, but
-- since right-click opens the settings menu, right-double
-- -click isn't possible.
end
-- MouseDown, MouseUp, and MouseMove are used to move the window (if not locked)
function self.caption.MouseDown(caption, args)
if (args.Button == Turbine.UI.MouseButton.Left) then
self.mouseDown = true;
self.originalMouseX, self.originalMouseY = Turbine.UI.Display.GetMouseX(), Turbine.UI.Display.GetMouseY();
end
end
function self.caption.MouseUp(caption, args)
if (args.Button == Turbine.UI.MouseButton.Left) then
self.mouseDown = false;
if (not self.settings.locked) then
if (self.parent:GetBarsMoveTogether()) then
self.parent:SnapToGrid("up");
else
self:SnapToGrid();
end
self:SaveSettings(false);
self.manager:HideGrid();
end
end
end
function self.caption.MouseMove(caption, args)
if (self.mouseDown and not self.settings.locked) then
self.mouseMoved = true;
local newMouseX, newMouseY = Turbine.UI.Display.GetMouseX(), Turbine.UI.Display.GetMouseY();
local deltaX, deltaY = newMouseX - self.originalMouseX, newMouseY - self.originalMouseY;
self.originalMouseX, self.originalMouseY = newMouseX, newMouseY;
-- See if we need to move other bars along with this one.
if (self.parent:GetBarsMoveTogether()) then
self.parent:OffsetPosition(deltaX, deltaY, "up");
else
self:OffsetPosition(deltaX, deltaY);
end
-- Display grid if "Snap to grid" is enabled.
if (self.globals.snapToGrid) then
local left, top, width, height = self:GetPosition();
if ((self.settings.orientation == "Right") or (self.settings.orientation == "Left")) then
width = self.displaySlots;
height = 1;
else
width = 1;
height = self.displaySlots;
end
self.manager:ShowGrid(left, top, width, height);
end
end
end
function self.caption.DragDrop(caption)
self:EditSequence();
end
end
local caption = self.caption;
if (not caption.label) then
caption.label = Turbine.UI.Label();
caption.label:SetParent(caption);
caption.label:SetMouseVisible(false);
end
local label = caption.label;
local alignment;
local where = self.settings.orientation;
if (self.settings.caption.position == "end") then
local swap = {Up = "Down"; Down = "Up"; Left = "Right"; Right = "Left"};
where = swap[where];
end
if (where == "Up") then
alignment = Turbine.UI.ContentAlignment.TopCenter;
elseif (where == "Down") then
alignment = Turbine.UI.ContentAlignment.BottomCenter;
elseif (where == "Right") then
alignment = Turbine.UI.ContentAlignment.MiddleRight;
else -- "Left"
alignment = Turbine.UI.ContentAlignment.MiddleLeft;
end
label:SetText(self.settings.caption.text);
label:SetVisible(not self.settings.caption.hidden);
self:FormatCaptionLabel(label, alignment);
if (self.captionEditor and self.captionEditor:WantsCaptionUpdates()) then
local textBox = self.captionEditor:GetTextBox();
self:FormatCaptionLabel(textBox, alignment);
self.captionEditor:Redraw();
end
end
function Bar:MouseArrive()
if (self.mouseInside) then
-- Already inside; do nothing.
return;
end
self.mouseInside = true;
DoCallbacks(self, "MouseArrived");
self:SetWantsUpdates(true);
end
function Bar:MouseDepart()
self.mouseInside = false;
DoCallbacks(self, "MouseDeparted");
end
function Bar:EditCaption()
if (self.captionEditor == nil) then
self.captionEditor = CaptionEditor("BarCaption", self, self.caption.label:GetWidth(), self.caption.label:GetHeight(), self.settings.caption.text);
self.captionEditor.Closed = function(sender, args)
self.captionEditor = nil;
end
end
end
function Bar:EditSequence()
if (self.sequenceEditor == nil) then
self.sequenceEditor = SequenceEditor(self, self.settings);
self.sequenceEditor.Closed = function(sender, args)
self.sequenceEditor = nil;
end
end
end
function Bar:FormatCaptionLabel(control, alignment)
control:SetFont(self.settings.caption.font);
control:SetForeColor(self.color);
control:SetFontStyle(Turbine.UI.FontStyle.Outline);
control:SetOutlineColor(Turbine.UI.Color(0.75, 0, 0, 0));
control:SetTextAlignment(alignment);
control:SetWidth(self.settings.caption.width);
control:SetHeight(self.settings.caption.height);
end
function Bar:MoveToMouseCursor()
cursorX, cursorY = self.slotContainer:PointToScreen(self.cursor:GetPosition());
cursorWidth, cursorHeight = self.cursor:GetSize();
cursorCenter = (cursorX + math.floor(cursorWidth / 2));
cursorMiddle = (cursorY + math.floor(cursorHeight / 2));
mouseX, mouseY = Turbine.UI.Display.GetMouseX(), Turbine.UI.Display.GetMouseY();
self:OffsetPosition(mouseX - cursorCenter, mouseY - cursorMiddle);
Turbine.UI.Window.Activate(self);
end
-- Bar is positioned with respect to the topmost/leftmost quickslot.
function Bar:GetSlotsScreenCoords()
local winLeft, winTop = Turbine.UI.Window.GetPosition(self);
local firstLeft, firstTop = self:GetSlotCoords(1);
local lastLeft, lastTop = self:GetSlotCoords(self.displaySlots);
local slotLeft, slotTop = math.min(firstLeft, lastLeft), math.min(firstTop, lastTop);
local slotRight = math.max(firstLeft, lastLeft) + self.settings.slotSize;
local slotBottom = math.max(firstTop, lastTop) + self.settings.slotSize;
local scale = self.globals.uiScale / 32;
-- If animating, use destination position (self.slotsLeft, self.slotsTop) rather than actual current position (self.slotContainer:GetPosition).
local left = winLeft + scale * (self.slotsLeft + slotLeft);
local top = winTop + scale * (self.slotsTop + slotTop);
local width = scale * (slotRight - slotLeft);
local height = scale * (slotBottom - slotTop);
return left, top, width, height;
end
function Bar:SetPosition(left, top)
local anchorLeft, anchorTop = self.manager:GetAnchorPosition(self.settings.anchor);
local changed = true;
if (left == nil) then
left = self.settings.position.left + anchorLeft;
top = self.settings.position.top + anchorTop;
changed = false;
end
local winLeft, winTop = Turbine.UI.Window.GetPosition(self);
local slotLeft, slotTop = self:GetSlotsScreenCoords();
local leftOffset, topOffset = slotLeft - winLeft, slotTop - winTop;
Turbine.UI.Window.SetPosition(self, left - leftOffset, top - topOffset);
if (changed) then
self.settings.position = { left = left - anchorLeft; top = top - anchorTop };
self:SaveSettings(false);
end
end
function Bar:SetAnchorPoint(anchor)
local left, top = self:GetPosition();
self.settings.anchor = anchor;
self:SetPosition(left, top);
end
-- Returns the position with respect to the top, left corner of the screen, regardless of anchor point.
function Bar:GetPosition()
local anchorLeft, anchorTop = self.manager:GetAnchorPosition(self.settings.anchor);
return anchorLeft + self.settings.position.left, anchorTop + self.settings.position.top;
end
function Bar:OffsetPosition(deltaX, deltaY)
local left, top = self:GetPosition();
self:SetPosition(left + deltaX, top + deltaY);
end
function Bar:SnapToGrid()
if (self:IsLocked() or (not self.globals.snapToGrid)) then
return;
end
local left, top = self:GetSlotsScreenCoords();
local newLeft, newTop = self.parent.manager:GetNearestGridPos(left, top);
self:SetPosition(newLeft, newTop);
self:SaveSettings(false);
end
function Bar:AddSettingsMenuItem(parent, itemName, fromOptionsPanel)
local item = Turbine.UI.MenuItem(L:GetText(itemName), true, false);
parent:GetItems():Add(item);
if (itemName == "Root") then
local prevContext = L:SetContext("/BarMenu");
parent:GetItems():Clear();
if (fromOptionsPanel and (not self:IsHidden())) then
self:AddSettingsMenuItem(parent, "Find");
end
self:AddSettingsMenuItem(parent, "Hide");
if (self.settings.visibleSlots > 1) then
if (self:IsCollapsed()) then
self:AddSettingsMenuItem(parent, "Expand");
else
self:AddSettingsMenuItem(parent, "Collapse");
end
end
self:AddSettingsMenuItem(parent, "Position");
self:AddSettingsMenuItem(parent, "Clone");
self:AddSettingsMenuItem(parent, "Delete");
self:AddSettingsMenuItem(parent, "Export");
self:AddSettingsMenuItem(parent, "EditSequence");
self:AddSettingsMenuItem(parent, "EventBehaviors");
self:AddSettingsMenuItem(parent, "Settings");
if (not fromOptionsPanel) then
if (self.parent ~= self.manager) then
self:AddSettingsMenuItem(parent, "Group");
end
Group.AddSettingsMenuItem(self.parent, parent, "Global", true);
self:AddSettingsMenuItem(parent, "Directory");
end
L:SetContext(prevContext);
elseif (itemName == "Expand") then
item.Click = function(sender, args)
self:Expand();
end
elseif (itemName == "Collapse") then
item.Click = function(sender, args)
self:Collapse();
end
elseif (itemName == "Directory") then
item.Click = function(sender, args)
self.manager.optionsPanel:ShowDirectory();
end
elseif (itemName == "Export") then
item.Click = function(sender, args)
self:Export();
end
elseif (itemName == "Find") then
item.Click = function(sender, args)
self:Find();
end
elseif (itemName == "Hide") then
item:SetChecked(self.settings.hidden);
item.Click = function(sender, args)
self:SetHidden(not self.settings.hidden);
end
elseif (itemName == "Position") then
local prevContext = L:SetContext("PositionMenu");
self:AddSettingsMenuItem(item, "LockPosition");
self:AddSettingsMenuItem(item, "RelativeTo");
L:SetContext(prevContext);
elseif (itemName == "LockPosition") then
item:SetChecked(self.settings.locked);
item.Click = function(sender, args)
self:SetLocked(not self.settings.locked);
end
elseif (itemName == "RelativeTo") then
local prevContext = L:SetContext("RelativeToMenu");
for text in values(L:GetSortedTexts()) do
local anchor = L:GetItem(text);
local newItem = self:AddSettingsMenuItem(item, anchor);
newItem:SetChecked(anchor == self.settings.anchor);
newItem:SetEnabled(anchor ~= self.settings.anchor);
newItem.Click = function(sender, args)
self:SetAnchorPoint(anchor);
end
end
L:SetContext(prevContext);
elseif (itemName == "EditSequence") then
item:SetEnabled(not self.sequenceEditor);
item.Click = function(sender, args)
self:EditSequence();
end
elseif (itemName == "EventBehaviors") then
local prevContext = L:SetContext("/EventBehaviorsMenu");
if (self.settings.eventsEnabled) then
if (#self.settings.eventHandlers > 0) then
self:AddSettingsMenuItem(item, "CurrentBehaviors");
end
self:AddSettingsMenuItem(item, "AddBehavior");
self:AddSettingsMenuItem(item, "DisableEvents");
else
self:AddSettingsMenuItem(item, "EnableEvents");
end
L:SetContext(prevContext);
elseif (itemName == "EnableEvents") then
item.Click = function()
self.settings.eventsEnabled = true;
self:SaveSettings(false);
self:SetWantsEvents(true);
end
elseif (itemName == "DisableEvents") then
item.Click = function()
self.settings.eventsEnabled = false;
self:SaveSettings(false);
self:SetWantsEvents(false);
end
elseif (itemName == "CurrentBehaviors") then
if (self.settings.eventHandlers) then
for h = 1, #self.settings.eventHandlers do
local handler = self.settings.eventHandlers[h];
local handlerItem = Turbine.UI.MenuItem(handler.description, true, false);
item:GetItems():Add(handlerItem);
local removeItem = Turbine.UI.MenuItem(L:GetText("Remove"), true, false);
handlerItem:GetItems():Add(removeItem);
removeItem.Click = function()
self:RemoveEventHandler(h);
end
end
end
elseif (itemName == "AddBehavior") then
local prevContext = L:SetContext("/EventBehaviorsMenu/Actions");
self:AddSettingsMenuItem(item, "ShowBar");
self:AddSettingsMenuItem(item, "HideBar");
self:AddSettingsMenuItem(item, "ResetBar");
self.availableEvents = self.manager:GetEventNames();
self:AddSettingsMenuItem(item, "MoveToCursor");
self:AddSettingsMenuItem(item, "ExpandBar");
self:AddSettingsMenuItem(item, "CollapseBar");
L:SetContext(prevContext);
elseif (string.find("|ShowBar|HideBar|ResetBar|MoveToCursor|ExpandBar|CollapseBar|", "|" .. itemName .. "|")) then
local prevContext = L:SetContext("/EventBehaviorsMenu/Triggers");
item.itemName = itemName;
self.availableEvents = self.manager:GetEventNames();
-- Show only the options that make sense
if (itemName ~= "MoveToCursor") then
if (itemName ~= "ResetBar") then
self:AddSettingsMenuItem(item, "AtStartup");
end
self:AddSettingsMenuItem(item, "WhenCombatBegins");
self:AddSettingsMenuItem(item, "WhenCombatEnds");
end
if ((itemName == "ResetBar") or (itemName == "ExpandBar")) then
self:AddSettingsMenuItem(item, "WhenMouseArrives");
end
if ((itemName == "ResetBar") or (itemName == "CollapseBar")) then
self:AddSettingsMenuItem(item, "WhenMouseDeparts");
end
if (itemName == "ResetBar") then
self:AddSettingsMenuItem(item, "WhenTraitTreeChanges");
end
self:AddSettingsMenuItem(item, "WhenEventOccurs");
L:SetContext(prevContext);
elseif (itemName == "WhenEventOccurs") then
if (#self.availableEvents > 0) then
for e = 1, #self.availableEvents do
local eventName = self.availableEvents[e];
local eventNameItem = Turbine.UI.MenuItem(eventName, true, false);
item:GetItems():Add(eventNameItem);
eventNameItem.Click = function()
self:AddEventHandler("WhenEventOccurs:" .. eventName, parent.itemName);
end
end
else
local noEventsItem = Turbine.UI.MenuItem(L:GetText("/EventBehaviorsMenu/NoEventsDefined"), false, false);
item:GetItems():Add(noEventsItem);
end
elseif (string.find("|AtStartup|WhenCombatBegins|WhenCombatEnds|WhenMouseArrives|WhenMouseDeparts|WhenTraitTreeChanges|", "|" .. itemName .. "|")) then
item.Click = function()
self:AddEventHandler(itemName, parent.itemName);
end
elseif (itemName == "Settings") then
local prevContext = L:SetContext("SettingsMenu");
self:AddSettingsMenuItem(item, "Orientation");
if ((self.settings.orientation == "Up") or (self.settings.orientation == "Down")) then
self:AddSettingsMenuItem(item, "Height");
else
self:AddSettingsMenuItem(item, "Width");
end
self:AddSettingsMenuItem(item, "Cursor");
self:AddSettingsMenuItem(item, "Caption");
self:AddSettingsMenuItem(item, "Color");
self:AddSettingsMenuItem(item, "Animation");
self:AddSettingsMenuItem(item, "HideAutomatics");
self:AddSettingsMenuItem(item, "HideInactiveBranches");
L:SetContext(prevContext);
elseif (itemName == "HideAutomatics") then
item:SetChecked(self.settings.hideAutomatics);
item.Click = function(sender, args)
self.settings.hideAutomatics = not self.settings.hideAutomatics;
self:SaveSettings(false);
self:ReapplySettings();
end
elseif (itemName == "HideInactiveBranches") then
item:SetChecked(self.settings.hideInactiveBranches);
item.Click = function(sender, args)
self.settings.hideInactiveBranches = not self.settings.hideInactiveBranches;
self:SaveSettings(false);
self:ReapplySettings();
end
elseif (itemName == "Color") then
item:SetEnabled(not self.colorPicker);
item.Click = function(sender, args)
self:EditColor();
end
elseif (itemName == "Animation") then
local prevContext = L:SetContext("AnimationMenu");
self:AddSettingsMenuItem(item, "Instantaneous");
self:AddSettingsMenuItem(item, "Fast");
self:AddSettingsMenuItem(item, "Slow");
self:AddSettingsMenuItem(item, "VerySlow");
self:AddSettingsMenuItem(item, "Disabled");
L:SetContext(prevContext);
elseif (string.find("|Instantaneous|Fast|Slow|VerySlow|Disabled|", "|" .. itemName .. "|")) then
local duration = { ["Instantaneous"] = 0; ["Fast"] = 0.05; ["Slow"] = 0.1; ["VerySlow"] = 0.5; ["Disabled"] = -1; };
local checked = (self.settings.animation.duration == duration[itemName]);
item:SetChecked(checked);
item:SetEnabled(not checked);
item.Click = function(sender, args)
self:SetAnimationSpeed(duration[itemName]);
end
elseif (itemName == "Orientation") then
local prevContext = L:SetContext("OrientationMenu");
self:AddSettingsMenuItem(item, "Up");
self:AddSettingsMenuItem(item, "Right");
self:AddSettingsMenuItem(item, "Left");
self:AddSettingsMenuItem(item, "Down");
L:SetContext(prevContext);
elseif ((itemName == "Up") or (itemName == "Down") or (itemName == "Left") or (itemName == "Right")) then
local checked = (self.settings.orientation == itemName);
item:SetChecked(checked);
item:SetEnabled(not checked);
item.Click = function(sender, args)
self.settings.orientation = itemName;
self:SaveSettings(false);
self:Redraw();
self:MoveOntoScreen();
end
elseif ((itemName == "Width") or (itemName == "Height")) then
local size = self.settings.visibleSlots;
local displayWidth, displayHeight = Turbine.UI.Display.GetSize();
local minSize = 1, maxSize;
if ((self.settings.orientation == "Up") or (self.settings.orientation == "Down")) then
maxSize = math.floor(displayHeight / self.settings.slotSize);
else
maxSize = math.floor(displayWidth / self.settings.slotSize);
end
local prevContext = L:SetContext("HeightWidthMenu");
for i = minSize, maxSize, 1 do
if (math.fmod (i, 20) == 0) then
local subItemName = ". . .";
local subItem = Turbine.UI.MenuItem(subItemName);
item:GetItems():Add(subItem);
item = subItem;
else
local subItemName = L:GetText("Slots");
if (i == 1) then
subItemName = L:GetText("Slot");
end
subItemName = string.gsub(subItemName, "<num>", tostring(i));
local checked = (i == self.settings.visibleSlots)
local subItem = Turbine.UI.MenuItem(subItemName, not checked, checked);
item:GetItems():Add(subItem);
subItem.Click = function(sender, args)
self:ResizeBar(i);
self:MoveOntoScreen();
end
end
end
L:SetContext(prevContext);
elseif (itemName == "Cursor") then
local prevContext = L:SetContext("CursorMenu");
self:AddSettingsMenuItem(item, "Style");
self:AddSettingsMenuItem(item, "HomePosition");
L:SetContext(prevContext);
elseif (itemName == "HomePosition") then
local prevContext = L:SetContext("HomePositionMenu");
for i = 1, self.settings.visibleSlots, 1 do
if (math.fmod (i, 20) == 0) then
local subItemName = ". . .";
local subItem = Turbine.UI.MenuItem(subItemName);
item:GetItems():Add(subItem);
item = subItem;
else
local subItemName = L:GetText("Slot");
subItemName = string.gsub(subItemName, "<num>", tostring(i));
local checked = (i == self.settings.cursorHomePosition);
local subItem = Turbine.UI.MenuItem(subItemName, not checked, checked);
item:GetItems():Add(subItem);
subItem.Click = function(sender, args)
self:Expand();
self.settings.cursorHomePosition = i;
self:SaveSettings(false);
self:Redraw();
end
end
end
L:SetContext(prevContext);
elseif (itemName == "Style") then
local prevContext = L:SetContext("StyleMenu");
local styles = {};
for name, info in pairs(resources.Cursor) do
local checked = (name == self.settings.cursorStyle);
local text = L:GetText(name);
local style = Turbine.UI.MenuItem(text, not checked, checked);
styles[text] = style;
style.Click = function(sender, args)
self:SetCursorStyle(name);
self:SaveSettings(false);
self:Redraw();
end
end
-- Display alphabetically.
for text in sorted_keys(styles) do
item:GetItems():Add(styles[text]);
end
L:SetContext(prevContext);
elseif (itemName == "Caption") then
local prevContext = L:SetContext("CaptionMenu");
self:AddSettingsMenuItem(item, "Edit");
self:AddSettingsMenuItem(item, "HideCaption");
self:AddSettingsMenuItem(item, "CaptionPosition");
L:SetContext(prevContext);
elseif (itemName == "Edit") then
item:SetEnabled(not self.captionEditor);
item.Click = function(sender, args)
self:EditCaption();
end
elseif (itemName == "HideCaption") then
item:SetChecked(self.settings.caption.hidden);
item.Click = function(sender, args)
self:SetCaptionHidden(not self.settings.caption.hidden);
end
elseif (itemName == "CaptionPosition") then
local prevContext = L:SetContext("CaptionPositionMenu");
if ((self.settings.orientation == "Up") or (self.settings.orientation == "Down")) then
self:AddSettingsMenuItem(item, "Top");
self:AddSettingsMenuItem(item, "Bottom");
else -- "Left" or "Right"
self:AddSettingsMenuItem(item, "LeftSide");
self:AddSettingsMenuItem(item, "RightSide");
end
L:SetContext(prevContext);
elseif (string.find("|Top|Bottom|LeftSide|RightSide|", "|" .. itemName .. "|")) then
local beginPosMap = { Left = "RightSide"; Right = "LeftSide"; Up = "Bottom"; Down = "Top" };
local amBeginPos = (itemName == beginPosMap[self.settings.orientation]);
local beginPosSelected = (self.settings.caption.position == "beginning");
local checked = (amBeginPos and beginPosSelected) or (not amBeginPos and not beginPosSelected);
local myOrientation = (amBeginPos and "beginning") or "end";
item:SetChecked(checked);
item:SetEnabled(not checked);
item.Click = function(sender, args)
self.settings.caption.position = myOrientation;
self:SaveSettings(false);
self:Redraw(true);
self:MoveOntoScreen();
end
elseif (itemName == "Clone") then
item.Click = function(sender, args)
self.parent:CloneBar(self.objectID);
end
elseif (itemName == "Group") then
self.parent.AddSettingsMenuItem(self.parent, item, "Root", true, self);
elseif (itemName == "Delete") then
item.Click = function(sender, args)
self.parent:DeleteBar(self.objectID);
end
end
return item;
end
function Bar:ResizeBar(size)
self:Expand();
self.settings.visibleSlots = size;
if (self.settings.cursorHomePosition > size) then
self.settings.cursorHomePosition = size;
end
self:SaveSettings(false);
self:Redraw();
end
function Bar:SetCursorStyle(style)
if (style == nil) then
style = self.settings.cursorStyle;
end
self.settings.cursorStyle = style;
local resource = resources.Cursor[style];
if (self.cursor) then
self.cursor:SetParent(nil);
self.cursor = nil;
end
self.cursor = Turbine.UI.Control();
self.cursor:SetParent(self.slotContainer);
self.cursor:SetMouseVisible(false);
if (resource.ApplyColor) then
self.cursor:SetBackColor(self.color);
end
local background = resources.Cursor[style].Background;
if (background) then
self.cursor:SetBackground(resource.Background);
self.cursorWidth, self.cursorHeight = GetAssetSize(resource.Background);
self.cursor:SetSize(self.cursorWidth, self.cursorHeight);
-- for now, presume square shape
self.cursorSize = math.ceil(self.cursorWidth / 2) * 2;
else
self.cursorSize = 36;
end
if (resource.BackColorBlendMode) then
self.cursor:SetBackColorBlendMode(resource.BackColorBlendMode);
end
if (resource.BlendMode) then
self.cursor:SetBlendMode(resource.BlendMode);
end
if (resource.ZOrder) then
self.cursor:SetZOrder(2 + resource.ZOrder);
end
-- self.cursor:SetVisible(not self:IsHidden());
if (not resource.xOffset) then
resource.xOffset = 0;
end
if (not resource.yOffset) then
resource.yOffset = 0;
end
self.cursorMargin = math.ceil((self.cursorSize - self.settings.slotSize) / 2);
self:SetCursorPos(self.cursorPos);
end
function Bar:SetLocked(state)
self.settings.locked = state;
self:SaveSettings(false);
end
function Bar:IsLocked()
return self.settings.locked;
end
-- Scrolls the sequence such that the specified slot appears under the cursor
function Bar:SetCursorSlot(slot)
local prevVisibleSlots = self.visibleSlots;
self.visibleSlots = {};
-- If advanced past the end of the sequence, start over at the beginning.
if (slot > #self.slots) then
slot = 1;
end
-- Find non-hidden slots to the left of the cursor
local gameTime = Turbine.Engine.GetGameTime();
local pos = self.cursorPos - 1;
local s = slot - 1;
while ((pos > 0) and (s > 0)) do
local object = self.slots[s];
if (not (object.hidden or (self.settings.hideInactiveBranches and self.sequence:SlotIsFolded(s, gameTime)))) then
self.visibleSlots[object] = pos;
pos = pos - 1;
end
s = s - 1;
end
self.cursorSlot = slot;
-- Find non-hidden slots to the right of the cursor.
-- Re-evaluate all conditionals except those to the left of the cursor.
pos = self.cursorPos;
s = slot;
while ((pos <= self.displaySlots) and (s <= #self.slots)) do
local object = self.slots[s];
if (object.info.type == "If") then
object.condResult = object.condFunc(object, self.manager.player) or false; -- nil => false
end
if (not (object.hidden or (self.settings.hideInactiveBranches and self.sequence:SlotIsFolded(s, gameTime)))) then
self.visibleSlots[object] = pos;
pos = pos + 1;
end
s = s + 1;
end
-- If no slots displayed, display the "reset" icon
if (pos == self.cursorPos) then
self.visibleSlots[self.resetSlot] = pos;
end
-- Make the old slots invisible
--if (self.settings.caption.text == "AoE Tank") then
-- Puts("prevVisibleSlots = " .. PrettyPrint(prevVisibleSlots, "", 1));
--end
for object, pos in pairs(prevVisibleSlots) do
if (not self.visibleSlots[object]) then
object:SetParent(nil);
object.pos = nil;
end
end
-- Make the new slots visible
--if (self.settings.caption.text == "AoE Tank") then
-- Puts("self.visibleSlots = " .. PrettyPrint(prevVisibleSlots, "", 1));
--end
if (not self.settings.hidden) then
for object, pos in pairs(self.visibleSlots) do
if (not prevVisibleSlots[object]) then
object:SetParent(self.slotContainer);
end
local left, top = self:GetSlotCoords(pos);
object:SetPosition(left - 1, top - 1);
object.pos = pos;
end
end
end
function Bar:SlotClick(s, automatic)
local slot = self.slots[s];
if (automatic) then
if (self.firstAutomaticClick) then
if (self.wrapped and (s >= self.firstAutomaticClick)) then
self.firstAutomaticClick = nil;
return;
end
else
self.firstAutomaticClick = s;
self.wrapped = false;
end
else
self.firstAutomaticClick = nil;
self.clickedPos = slot.pos;
self.clickedSlot = s;
end
-- Do the action associated with the slot, if any
if (slot.actionFunc) then
slot:actionFunc(s);
end
-- Process conditionals (if/then/else).
if (slot.info.type == "If") then
slot.condResult = slot.condFunc(slot, self.manager.player) or false; -- nil => false
if (not slot.condResult) then
if (slot.elseSlot) then
s = slot.elseSlot - 1;
elseif (slot.endIfSlot) then
s = slot.endIfSlot - 1;
end
end
elseif (slot.info.type == "Else") then
doElse = true;
if (slot.ifSlot) then
doElse = not self.slots[slot.ifSlot].condResult;
end
if (slot.endIfSlot and not doElse) then
s = slot.endIfSlot - 1;
end
end
local nextSlot = s + 1;
-- If a previous advancement callback was never called, unregister it.
self:UnregisterAdvanceCallback();
if (slot.info.advanceEvent) then
local object, event;
if (slot.info.advanceEvent == "ItemEquipped") then
if (not IsEquipped(slot.object:GetShortcut():GetItem():GetItemInfo():GetName())) then
object = Thurallor.Utils.Watcher;
event = "ItemEquipped";
end
elseif (slot.info.advanceEvent == "DelayComplete") then
object = slot;
event = "Reset";
-- elseif (slot.info.advanceEvent == "SkillCooldownBegun") then
end
if (object) then
slot.advanceFunc = function()
self:AdvanceToSlot(nextSlot);
RemoveCallback(object, event, slot.advanceFunc);
end
AddCallback(object, event, slot.advanceFunc);
self.advancement = { object = object, event = event, func = slot.advanceFunc };
-- Wait for an event before advancing.
return;
end
end
-- Advance immediately.
self:AdvanceToSlot(nextSlot);
end
function Bar:StartSlotCooldown(s, delay)
local slot = self.slots[s];
slot.hiddenAfterReset = slot.hidden;
slot.hidden = false;
self:SetCursorPos(self.clickedPos);
self:SetCursorSlot(s);
slot:StartCooldown(delay);
end
function Bar:UnregisterAdvanceCallback()
if (self.advancement) then
RemoveCallback(self.advancement.object, self.advancement.event, self.advancement.func);
self.advancement = nil;
end
end
function Bar:AdvanceToSlot(s)
if (s > #self.slots) then
self.wrapped = true;
s = 1;
end
local slot = self.slots[s];
-- If the user didn't click on the currently selected slot, move the cursor.
if (self.clickedPos ~= self.cursorPos) then
self:SetCursorPos(self.clickedPos);
end
-- If the next slot is automatic, auto-click it.
if (slot.info.automatic) then
self:SetCursorSlot(s);
return self:SlotClick(s, true);
end
-- If animation is disabled via settings, or stopped via a "Stop" slot, refold the slots and do nothing further.
if ((self.settings.animation.duration == -1) or self.animationStopped) then
self:SetCursorSlot(self.clickedSlot);
return;
end
-- Do animation.
self:SetCursorSlot(s);
if (self.settings.animation.duration > 0) then
self:Animate(0);
end
end
function Bar:Update()
if (self.animationStartTime) then
local timeDelta = Turbine.Engine.GetGameTime() - self.animationStartTime;
if (timeDelta > 0) then
self:Animate(timeDelta);
end
end
-- if (self.delayedClick) then
-- self:SlotClick(self.delayedClick, true);
-- end
if (self.mouseInside) then
local mouseLeft, mouseTop = Turbine.UI.Display:GetMousePosition();
local left, top, width, height = self:GetSlotsScreenCoords();
if ((mouseLeft < left) or (mouseLeft >= left + width) or (mouseTop < top) or (mouseTop >= top + height)) then
self:MouseDepart();
end
end
if ((not self.animationStartTime) and (not self.mouseInside)) then
-- and (not self.delayedClick)
self:SetWantsUpdates(false);
end
end
function Bar:SetAnimationSpeed(duration)
self.settings.animation.duration = duration;
self:SaveSettings(false);
end
-- Achieves the scrolling effect. Gets called by Bar:Update().
function Bar:Animate(timeDelta)
local progress = timeDelta / self.settings.animation.duration;
if (progress == 0) then
self.animationStartTime = Turbine.Engine.GetGameTime();
self.animationDistance = self.settings.slotSize + self.settings.slotSpacing;
self:SetWantsUpdates(true);
elseif (progress >= 1) then
progress = 1;
self.animationStartTime = nil;
end
local displacement = math.floor(self.animationDistance * (1 - progress));
if (self.settings.orientation == "Up") then
self.slotContainer:SetTop(self.slotsTop - displacement);
elseif (self.settings.orientation == "Down") then
self.slotContainer:SetTop(self.slotsTop + displacement);
elseif (self.settings.orientation == "Left") then
self.slotContainer:SetLeft(self.slotsLeft - displacement);
elseif (self.settings.orientation == "Right") then
self.slotContainer:SetLeft(self.slotsLeft + displacement);
end
-- Make sure the item under the cursor is always clickable. This hack is
-- necessary because as the slot moves, no MouseEnter event occurs and
-- hence no MouseClick events can be received.
self.slots[self.cursorSlot]:SetVisible(false);
self.slots[self.cursorSlot]:SetVisible(true);
end
function Bar:Destroy()
if (self.sequenceEditor) then
self.sequenceEditor:Close();
end
-- Unregister as event generator
for eventName, generatorID in pairs(self.eventGeneratorIDs) do
self.manager:RemoveEventGenerator(generatorID, eventName);
end
Node.Destroy(self);
self.manager:SetIncludees(self.objectID, nil);
end
function Bar:GetVisibleLeft()
local left = self:GetSlotsScreenCoords();
return left;
end
function Bar:SetVisibleLeft(left)
self:OffsetPosition(left - self:GetVisibleLeft(), 0);
end
function Bar:GetVisibleTop()
local _, top = self:GetSlotsScreenCoords();
return top;
end
function Bar:SetVisibleTop(top)
self:OffsetPosition(0, top - self:GetVisibleTop());
end
function Bar:GetVisibleWidth()
local _, _, width = self:GetSlotsScreenCoords();
return width;
end
function Bar:GetVisibleHeight()
local _, _, _, height = self:GetSlotsScreenCoords();
return height;
end
function Bar:GetSlotCoords(slot)
local slotSize = self.settings.slotSize + self.settings.slotSpacing;
local offset = self.cursorMargin + (slot - 1) * slotSize;
local left, top;
if (self.settings.orientation == "Up") then
left = self.cursorMargin;
top = self.slotContainer:GetHeight() - slotSize - offset;
elseif (self.settings.orientation == "Down") then
left = self.cursorMargin;
top = offset;
elseif (self.settings.orientation == "Left") then
left = self.slotContainer:GetWidth() - slotSize - offset;
top = self.cursorMargin;
else -- "Right"
left = offset;
top = self.cursorMargin;
end
return left, top
end
function Bar:Find()
self:MoveOntoScreen();
Turbine.UI.Window.Activate(self);
self:Flash();
end
function Bar:MoveOntoScreen()
local screenWidth, screenHeight = Turbine.UI.Display:GetWidth(), Turbine.UI.Display:GetHeight();
local left, top = self:PointToScreen(self.caption:GetLeft(), self.caption:GetTop());
local right, bottom = left + self.caption:GetWidth(), top + self.caption:GetHeight();
local deltaX, deltaY = 0, 0;
if (left < 0) then
deltaX = -left;
elseif (right > screenWidth) then
deltaX = screenWidth - right;
end
if (top < 0) then
deltaY = -top;
elseif (bottom > screenHeight) then
deltaY = screenHeight - bottom;
end
self:OffsetPosition(deltaX, deltaY);
self:SnapToGrid();
end
function Bar:Flash()
self:Activate();
self.caption.startTime = Turbine.Engine.GetGameTime();
self.caption.label:SetVisible(true);
if (not self.marquee) then
self.marquee = Thurallor.UI.Marquee();
self.marquee:SetParent(self);
self.marquee:SetSize(self:GetSize());
end
self.caption.Update = function(caption, args)
local timeDelta = Turbine.Engine.GetGameTime() - caption.startTime;
if (timeDelta > 3) then
caption.label:SetForeColor(self.color);
caption.label:SetVisible(not self.settings.caption.hidden);
caption:SetWantsUpdates(false);
self.marquee:SetParent(nil);
self.marquee = nil;
else
local progress = (math.sin(timeDelta * 15) + 1) / 2; --math.modf(timeDelta / 0.3);
caption.label:SetForeColor(Turbine.UI.Color(progress, 1, 1, 0));
end
end
self.caption:SetWantsUpdates(true);
end