Tab = class(Thurallor.UI.TabCard);
local importPath = getfenv(1)._.Name;
local imagePath = string.gsub(string.gsub(importPath, "%.Tab$", ""), "%.", "/") .. "/Images/";
function Tab:Constructor(window, settings)
Thurallor.UI.TabCard.Constructor(self, false, false, true, true);
self.window = window;
AddCallback(self.tabText, "MouseEnter", function(ctl)
self.window.shimmering:Remove(ctl);
end);
self.settings = self:UpdateSettings(settings);
self:SetTabText(settings.name);
self:SetTabLeft(settings.tabLeft);
self.table = Thurallor.UI.TableControl();
-- Apply user's color preference to tab and table
color = Thurallor.Utils.Color(unpack(self.settings.color));
self.color = color;
local H, S, V = color:GetHSV();
color:SetHSV(H, S, 1);
local A, R, G, B = 1, color.R, color.G, color.B;
self:SetTabColor(Turbine.UI.Color(A, R, G, B));
self:SetBackColor(Turbine.UI.Color(A, R/6, G/6, B/6));
local style = self.table:GetStyle();
style.heading.BackColor = Turbine.UI.Color(A, R*2/3, G*2/3, B*2/3);
style.heading.HighlightColor = Turbine.UI.Color(A, R, G, B);
style.cell.BackColor = Turbine.UI.Color(A, R/3, G/3, B/3);
style.cell.HighlightColor = Turbine.UI.Color(A, R, G, B);
style.edgeMover.BackColor = Turbine.UI.Color(A*3/4, R/3, G/3, B/3);
style.marquee.Color = color:SetHSV(H, S, 0.75);
style.marquee.AntsEnabled = window.settings.marqueeAntsEnabled or false;
self.table:SetStyle(style);
self.table:SetParent(self);
local function valueSort(a, b)
local aValue, bValue = a.sortValue, b.sortValue;
if (aValue < bValue) then
return -1;
elseif (aValue > bValue) then
return 1;
else
return 0;
end
end
local prevContext = L:SetContext("/MainWindow/ColumnHeadings");
self.table:AddColumn("checkbox", L:GetText("Checkbox"), 0.5, valueSort);
self.table:AddColumn("desc", L:GetText("Description"), 2, nil);
self.table:AddColumn("location", L:GetText("Location"), 1, valueSort);
self.table:AddColumn("distance", L:GetText("Distance"), 1, valueSort);
self.table:AddColumn("category", L:GetText("Category"), 1, nil);
self.table:AddColumn("charName", L:GetText("Character"), 1, nil);
self.table:AddColumn("serverID", L:GetText("Server"), 0, nil);
self.table:AddColumn("remaining", L:GetText("Time"), 1, valueSort);
self.table:AddColumn("resetTimes", L:GetText("NextReset"), 1, valueSort);
self.table:AddColumn("notes", L:GetText("Notes"), 0, nil);
AddCallback(self.table, "PresentationChanged", function(_, args)
self.settings.presentation = self.table:GetPresentation();
self:SaveSettings();
end);
AddCallback(self.table, "SelectionChanged", function(_, args)
self:SelectionChanged(args);
end);
-- Configure the column heading for the "Checkbox" column
local heading = self.table:GetHeading("checkbox");
heading:SetText("");
heading.GetText = function() return L:GetText("/MainWindow/ColumnHeadings/Checkbox"); end;
local checkBox = Turbine.UI.Lotro.CheckBox();
checkBox:SetParent(heading);
checkBox:SetZOrder(1);
checkBox:SetSize(16, 16);
checkBox.CheckedChanged = function(ctl)
if (not self.table.IsColumnLocked("checkbox")) then
local checked = ctl:IsChecked();
self:ForEachEventDo(function(event) event:SetChecked(checked); end);
end
end
function heading.SetWidth(ctl, width)
Turbine.UI.Lotro.TextBox.SetWidth(ctl, width);
checkBox:SetPosition(width - 19, 4);
end
heading:SetWidth(heading:GetWidth());
-- Configure the column heading for the "Distance" column
local heading = self.table:GetHeading("distance");
AddCallback(heading, "MouseEnter", function(ctl)
if (not self.table:IsColumnLocked("distance")) then
self.calc_icon:SetBackground(self.calc_icon.bgNormal);
self.calc_icon:SetParent(ctl:GetParent());
self.calc_icon:SetVisible(true);
self.calc_icon:SetPosition(ctl:GetLeft() + ctl:GetWidth() - 23, 1);
self.calc_icon:SetZOrder(4);
self.window.LocationChanged = function()
self:UpdateDistanceColumn(self.window.location);
end
ctl:SetWantsUpdates(true);
end
end);
-- In lieu of MouseLeave event handler:
AddCallback(heading, "Update", function(ctl)
local x, y = ctl:GetMousePosition();
local w, h = ctl:GetSize();
if ((x < 0) or (y < 0) or (x >= w) or (y >= h)) then
self.calc_icon:SetVisible(false);
ctl:SetWantsUpdates(false);
end
end);
L:SetContext(prevContext);
self:SetInteriorControl(self.table);
self:SetInteriorAlignment(Turbine.UI.ContentAlignment.TopLeft);
-- Create row overlay icons: X, settings, reset, target, waypoint, calculate
self.x_icon = self:CreateIcon(Turbine.UI.Control(), "x.tga", "x_highlight.tga");
Thurallor.UI.Tooltip(L:GetText("/MainWindow/DeleteThisReminder")):Attach(self.x_icon);
self.settings_icon = self:CreateIcon(Turbine.UI.Control(), "settings.tga", "settings_highlight.tga");
Thurallor.UI.Tooltip(function()
local _, _, _, gameTime = unpack(self.settings_icon.event:GetLastAutomaticUpdate());
local interval = Turbine.Engine.GetGameTime() - gameTime;
local intervalStr = Time.GetDelayStr(interval, false, true);
return L:GetText("/MainWindow/AutomaticReminderSettings"):gsub("<interval>", intervalStr);
end):Attach(self.settings_icon);
self.reset_icon = self:CreateIcon(Turbine.UI.Control(), "next_login.tga", "next_login_highlight.tga");
Thurallor.UI.Tooltip(function()
return self.reset_icon.event:GetPostponeStr() .. "\n" .. L:GetText("/PostponeTimeDialog/TooltipRightClick");
end):Attach(self.reset_icon);
local cmd = "/" .. L:GetText("/ShellCommand/Command") .. " " .. L:GetText("/ShellCommand/SetLoc") .. " " .. L:GetClientLanguageText("/Chat/loc");
local baseCtl = Thurallor.UI.TrickButton(cmd, Turbine.ChatType.Standard, nil);
self.target_icon = self:CreateIcon(baseCtl, "location.tga", "location_highlight.tga");
local tooltip = Thurallor.UI.Tooltip(L:GetText("/MainWindow/DetectLocation"));
tooltip:Attach(self.target_icon);
tooltip:SetWantsUpdates(true);
baseCtl = Thurallor.UI.TrickButton(cmd, Turbine.ChatType.Standard, nil);
self.calc_icon = self:CreateIcon(baseCtl, "calc.tga", "calc_highlight.tga");
Thurallor.UI.Tooltip(L:GetText("/MainWindow/CalculateDistances")):Attach(self.calc_icon);
baseCtl = Thurallor.UI.TrickButton("/way", Turbine.ChatType.Standard, nil);
self.waypoint_icon = self:CreateIcon(baseCtl, "waypoint.tga", "waypoint_highlight.tga");
Thurallor.UI.Tooltip(L:GetText("/MainWindow/SetWaypointTarget")):Attach(self.waypoint_icon);
self.events = {};
self:SendToBack();
self:CreateSavedEvents();
self:UpdateDistanceColumn();
self.table:SetPresentation(self.settings.presentation);
end
function Tab:GetHighlightColor()
local style = self.table:GetStyle();
return style.cell.HighlightColor;
end
function Tab:GetCellColor()
local style = self.table:GetStyle();
return style.cell.BackColor;
end
function Tab:Click(args)
if (args.Button == Turbine.UI.MouseButton.Left) then
self.window.settings.frontTab = self.settings.name;
self:SaveSettings();
elseif (args.Button == Turbine.UI.MouseButton.Right) then
self:ShowTabContextMenu();
end
end
function Tab:DoubleClick(args)
if (args.Button == Turbine.UI.MouseButton.Left) then
self:OpenRenameDialog();
end
end
-- Fill in any new settings that have been added if the plugin has been updated
function Tab:UpdateSettings(settings)
settings = settings or {};
settings.color = settings.color or { 1, 0, 0.57, 1};
settings.presentation = settings.presentation or {};
settings.presentation.columns = settings.presentation.columns or {
{ "desc", 3 }, { "category", 1 }, { "charName", 1 }, { "remaining", 1 },
};
settings.tabLeft = settings.tabLeft or 0;
settings.events = settings.events or {};
if (settings.updateIcon == nil) then
settings.updateIcon = true;
end
return settings;
end
function Tab:ShowTabContextMenu(fromSettingsWindow)
local contextMenu = Turbine.UI.ContextMenu();
local menuItems, item = contextMenu:GetItems();
local prevContext = L:SetContext("/MainWindow/TabContextMenu");
if (not fromSettingsWindow) then
item = Turbine.UI.MenuItem(L:GetText("CreateTab"));
item.Click = function()
self.window:CreateNewTab();
end
menuItems:Add(item);
end
item = Turbine.UI.MenuItem(L:GetText("CreateItinerary") .. "...");
item.Click = function()
self:OpenItineraryDialog();
end
menuItems:Add(item);
item = Turbine.UI.MenuItem(L:GetText("RenameTab"));
item.Click = function()
self:OpenRenameDialog();
end
menuItems:Add(item);
item = Turbine.UI.MenuItem(L:GetText("Color"));
item.Click = function()
self:OpenColorPicker();
end
menuItems:Add(item);
item = Turbine.UI.MenuItem(L:GetText("CloneTab"));
item.Click = function()
self.window:CloneTab(self.settings.name);
end
menuItems:Add(item);
local tabNames = self.window:GetUserTabs();
if (#tabNames > 1) then
item = Turbine.UI.MenuItem(L:GetText("MergeWithOtherTab"));
menuItems:Add(item);
local subItems = item:GetItems();
for _, name in ipairs(tabNames) do
if (name ~= self.settings.name) then
local subItem = Turbine.UI.MenuItem(name);
subItem.Click = function(ctl)
self.window:MergeTabs(self.settings.name, ctl:GetText());
end
subItems:Add(subItem);
end
end
end
item = Turbine.UI.MenuItem(L:GetText("DeleteTab"));
item.Click = function()
if (self.window.settings.askBeforeDeleting) then
if (not self.confirmDialog) then
self.confirmDialog = ConfirmDialog(self.window, L:GetText("/MainWindow/TabContextMenu/DeleteTab"));
self.confirmDialog.Yes = function(_, arg)
self.window:DeleteTab(self.settings.name);
self.confirmDialog = nil;
end
self.confirmDialog.No = function(_, arg)
self.confirmDialog = nil;
end
end
else
self.window:DeleteTab(self.settings.name);
end
end
menuItems:Add(item);
if (self.window:GetNumUserTabs() < 2) then
-- Can't delete last remaining tab.
item:SetEnabled(false);
end
item = Turbine.UI.MenuItem(L:GetText("OtherOptions"));
item.Click = function(ctl)
self.window.optionsPanel:ShowTabSettings(self.settings.name);
self.window.optionsPanel:SetVisible(false);
self.zoomer = Thurallor.UI.Zoomer(self.tabText, self.window.optionsPanel);
AddCallback(self.zoomer, "ZoomComplete", function()
self.window.optionsPanel:SetVisible(true);
end);
end;
menuItems:Add(item);
L:SetContext(prevContext);
contextMenu:ShowMenu();
end
function Tab:ShowEventContextMenu(event)
local contextMenu = Turbine.UI.ContextMenu();
local menuItems, item = contextMenu:GetItems();
local prevContext = L:SetContext("/MainWindow/EventContextMenu");
item = Turbine.UI.MenuItem(L:GetText("MoveToOtherTab"));
menuItems:Add(item);
if (self.window:GetNumUserTabs() == 1) then
item:SetEnabled(false);
else
-- Submenu with a list of tabs
local subMenuItems = item:GetItems();
local tabNames = self.window:GetUserTabs();
for _, name in ipairs(tabNames) do
if (name ~= self.settings.name) then
local subItem = Turbine.UI.MenuItem(name);
subItem.Click = function()
local otherTab = self.window:GetTab(name);
otherTab:CloneEvent(event);
self:DeleteEvent(event);
end
subMenuItems:Add(subItem);
end
end
end
item = Turbine.UI.MenuItem(L:GetText("CopyToOtherTab"));
menuItems:Add(item);
if (self.window:GetNumUserTabs() == 1) then
item:SetEnabled(false);
else
-- Submenu with a list of tabs
local subMenuItems = item:GetItems();
local tabNames = self.window:GetUserTabs();
for _, name in ipairs(tabNames) do
if (name ~= self.settings.name) then
local subItem = Turbine.UI.MenuItem(name);
subItem.Click = function()
local otherTab = self.window:GetTab(name);
otherTab:CloneEvent(event);
end
subMenuItems:Add(subItem);
end
end
end
local item = Turbine.UI.MenuItem(L:GetText("Clone"));
item.Click = function()
self:CloneEvent(event);
end
menuItems:Add(item);
local item = Turbine.UI.MenuItem(L:GetText("Delete"));
item.Click = function()
self:DeleteEvent(event);
end
menuItems:Add(item);
local item = Turbine.UI.MenuItem(L:GetText("AddDay"));
item.Click = function()
event:SetExpirationTime(event:GetExpirationTime() + 24 * 60 * 60);
self:SaveSettings();
end
menuItems:Add(item);
local item = Turbine.UI.MenuItem(L:GetText("AddWeek"));
item.Click = function()
event:SetExpirationTime(event:GetExpirationTime() + 7 * 24 * 60 * 60);
self:SaveSettings();
end
menuItems:Add(item);
L:SetContext(prevContext);
contextMenu:ShowMenu();
end
function Tab:SetTabLeft(left)
Thurallor.UI.TabCard.SetTabLeft(self, left);
self.settings.tabLeft = left;
self:SaveSettings();
end
function Tab:Rename(newName)
if (newName ~= self.settings.name) then
self.window:RenameTab(self.settings.name, newName);
end
end
function Tab:OpenRenameDialog()
local win = Turbine.UI.Lotro.Window();
win:SetText(L:GetText("/RenameTabDialog/Title"));
win:SetSize(250, 100);
win:SetVisible(true);
win:SetZOrder(self.window:GetZOrder() + 1);
local textBox = Turbine.UI.Lotro.TextBox();
textBox:SetParent(win);
textBox:SetPosition(5, 44);
textBox:SetSize(240, 24);
textBox:SetFont(Turbine.UI.Lotro.Font.Verdana14);
textBox:SetTextAlignment(Turbine.UI.ContentAlignment.MiddleCenter);
textBox:SetMultiline(false);
textBox:SetText(self.settings.name);
textBox:SelectAll();
textBox:Focus();
EnableEnterEscHandling(win);
win.EnterKeyPressed = function(w)
local newName = textBox:GetText();
if ((newName == "") or (self.window:GetTab(newName) and (newName ~= self.settings.name))) then
-- Unacceptable.
textBox:SetText(self.settings.name);
textBox:SelectAll();
return;
end
w:Close();
self:Rename(newName);
end
win.EscapeKeyPressed = function(w)
w:Close();
end
win:Activate();
self.window:WaitForChild(win);
-- Position the window over the mouse cursor:
self.window.mask:MouseClick();
end
function Tab:OpenItineraryDialog()
local dialog = ItineraryDialog(self.window);
self.window:WaitForChild(dialog);
-- Position the window over the mouse cursor:
self.window.mask:MouseClick();
end
function Tab:OpenColorPicker()
local picker = Thurallor.UI.ColorPicker(self:GetTabColor());
picker:SetZOrder(self.window:GetZOrder() + 1);
picker:FreezeDimension("V", 0.6);
picker.Accepted = function(p)
local color = p:GetColor();
self.settings.color = { color.A, color.R, color.G, color.B };
self.window:RebuildTabs();
end
self.window:WaitForChild(picker);
-- Position the window over the mouse cursor:
self.window.mask:MouseClick();
end
function Tab:CreateIcon(baseControl, normalImage, highlightImage)
local icon = baseControl;
icon:SetBlendMode(Turbine.UI.BlendMode.Overlay);
icon:SetSize(22, 22);
icon.bgNormal = Turbine.UI.Graphic(imagePath .. normalImage);
icon.bgHighlight = Turbine.UI.Graphic(imagePath .. highlightImage);
function icon.IsMouseOver(ctl)
local x, y = ctl:GetMousePosition();
return ((x >= 0) and (y >= 0) and (x < 22) and (y < 22));
end
AddCallback(icon, "MouseEnter", function(ctl)
ctl:SetBackground(ctl.bgHighlight);
end);
AddCallback(icon, "MouseLeave", function(ctl)
ctl:SetBackground(ctl.bgNormal);
end);
return icon;
end
function Tab:ShowResetIcon(parent, left, top, event)
self.reset_icon.event = event; -- needed for tooltip
self.reset_icon:SetBackground(self.reset_icon.bgNormal);
self.reset_icon:SetParent(parent);
self.reset_icon:SetVisible(true);
self.reset_icon:SetPosition(left, top);
self.reset_icon:SetZOrder(4); -- in front of mask
self.reset_icon.MouseClick = function(b, args)
if (args.Button == Turbine.UI.MouseButton.Left) then
event:Postpone();
self:ReapplySort("remaining");
event:SaveSettings();
b:SetVisible(false);
elseif (args.Button == Turbine.UI.MouseButton.Right) then
if (b.dialog) then
b.dialog:Close();
end
b.dialog = PostponeTimeDialog(event);
AddCallback(b.dialog, "Closing", function()
b.dialog = nil;
end);
end
end
return self.reset_icon;
end
function Tab:ShowTargetIcon(parent, left, top, event)
self.target_icon:SetBackground(self.target_icon.bgNormal);
self.target_icon:SetParent(parent);
self.target_icon:SetVisible(true);
self.target_icon:SetPosition(left, top);
self.target_icon:SetZOrder(4); -- in front of mask
self.window.LocationChanged = function()
event:SetLocation(self.window.location);
event:SaveSettings();
end
return self.target_icon;
end
function Tab:ShowWaypointIcon(parent, left, top, event)
local _, coords = event:GetLocation();
if (coords and Turbine.Shell.IsCommand("waypoint")) then
self.waypoint_icon:SetBackground(self.waypoint_icon.bgNormal);
self.waypoint_icon:SetParent(parent);
self.waypoint_icon:SetVisible(true);
self.waypoint_icon:SetPosition(left, top);
self.waypoint_icon:SetZOrder(4); -- in front of mask
self.waypoint_icon:SetCommand("/way target " .. coords);
end
return self.waypoint_icon;
end
function Tab:ShowXIcon(parent, left, top, event)
self.x_icon:SetBackground(self.x_icon.bgNormal);
self.x_icon:SetParent(parent);
self.x_icon:SetVisible(true);
self.x_icon:SetPosition(left, top);
self.x_icon:SetZOrder(4); -- in front of mask
self.x_icon.MouseClick = function(ctl, args)
if (args.Button == Turbine.UI.MouseButton.Left) then
if (self.window.settings.askBeforeDeleting) then
if (not ctl.confirmDialog) then
ctl.confirmDialog = ConfirmDialog(self.window, L:GetText("/MainWindow/DeleteThisReminder"));
ctl.confirmDialog.Yes = function(_, arg)
self:DeleteEvent(event);
ctl.confirmDialog = nil;
end
ctl.confirmDialog.No = function(_, arg)
ctl.confirmDialog = nil;
end
end
else
self:DeleteEvent(event);
end
end
end
return self.x_icon;
end
function Tab:ShowSettingsIcon(parent, left, top, event)
local charID = unpack(event:GetLastAutomaticUpdate() or {});
if (charID) then
local charSettings = self.window.settings.characters[charID];
if (not charSettings) then
-- If the settings for this character no longer exist, we can't display them
return;
end
end
self.settings_icon.event = event; -- needed for tooltip
self.settings_icon:SetBackground(self.settings_icon.bgNormal);
self.settings_icon:SetParent(parent);
self.settings_icon:SetVisible(true);
self.settings_icon:SetPosition(left, top);
self.settings_icon:SetZOrder(4); -- in front of mask
self.settings_icon.MouseClick = function(ctl, args)
if (args.Button == Turbine.UI.MouseButton.Left) then
local charID, itemType, item, gameTime = unpack(event:GetLastAutomaticUpdate() or {});
if (charID) then
local charSettings = self.window.settings.characters[charID];
if (charSettings) then
local settings = charSettings.autoReminders[itemType];
local control1, control2 = self.window.optionsPanel:ShowHighlightArea(charID, itemType);
if (itemType == "quests") then
settings = settings.questInfo[item];
if (settings) then
control2 = QuestRepeatedDialog.GetInstance(self.window, item, settings, charSettings, charID);
end
elseif (itemType == "raidlocks") then
settings = settings.lockInfo[item];
if (settings) then
control2 = RaidLockDialog.GetInstance(self.window, item, settings, charSettings, charID);
end
end
self.zoomer1 = Thurallor.UI.Zoomer(self.settings_icon, control1);
control1:SetVisible(false);
self.zoomer1 = Thurallor.UI.Zoomer(self.settings_icon, control1);
AddCallback(self.zoomer1, "ZoomComplete", function()
control1:SetVisible(true);
end);
if (control2) then
control2:SetVisible(false);
self.zoomer2 = Thurallor.UI.Zoomer(self.settings_icon, control2);
AddCallback(self.zoomer2, "ZoomComplete", function()
control2:SetVisible(true);
control2:Activate();
end);
end
end
end
end
end
return self.settings_icon;
end
function Tab:SizeChanged()
self.table:SetSize(self:GetWidth() - 10, self:GetHeight() - 30);
end
function Tab:TabLeftChanged(tabLeft)
self.settings.tabLeft = tabLeft;
if (tabLeft == 0) then
-- Ensure that this tab appears to the left of any other
self:SetTabLeft(-1);
end
self:GetParent():RedistributeTabs(); -- includes save
end
-- Finds the matching event with the oldest expiration time that is not "never".
-- Search criteria can be disabled by setting the corresponding argument to nil.
function Tab:FindOldestMatchingEvent(desc, charID, category, isExpired, location, checked)
local oldestEvent = nil;
local oldestExpTime = 10000000000000;
for event, settings in pairs(self.events) do
if ((desc == nil) or (desc == event:GetDescription())) then
if ((charID == nil) or (charID == event:GetCharacterID())) then
if ((category == nil) or (category == event:GetCategory())) then
-- if ((isExpired == nil) or (isExpired == event:IsExpired())) then
-- if ((location == nil) or (location == event:GetLocation())) then
-- if ((checked == nil) or (checked == event:IsChecked())) then
local expTime = event:GetExpirationTime();
if ((expTime >= 0) and (expTime < oldestExpTime)) then
oldestEvent = event;
end
-- end
-- end
-- end
end
end
end
end
return oldestEvent;
end
function Tab:CloneEvent(oldEvent)
local settings = DeepTableCopy(oldEvent.settings);
local newEvent = self:CreateEvent(settings, false);
if (newEvent) then
table.insert(self.settings.events, settings);
self.events[newEvent] = settings;
return newEvent;
end
end
-- To do: Get rid of this wrapper
function Tab:CreateNewEvent(desc, charID, expTime, resetTimes, category, location, checked)
local settings = {
desc = desc;
charID = charID;
expTime = expTime;
resetTimes = resetTimes;
rotation = nil;
category = category;
location = location;
checked = checked;
};
return self:CreateNewEvent2(settings);
end
function Tab:CreateNewEvent2(settings)
settings = settings or {};
local event = self:CreateEvent(settings, false);
if (event) then
table.insert(self.settings.events, settings);
self.events[event] = settings;
return event;
end
end
function Tab:CreateSavedEvents()
self.charID = self.window.charID;
self.serverRegexp = "^" .. self.window.serverID .. "%.";
local scope = self.window.settings.viewingScope;
if (scope == "account") then
self.eventInScope = function()
return true;
end;
elseif (scope == "server") then
self.eventInScope = function(charID)
return charID:match(self.serverRegexp);
end;
else -- (scope == "character")
self.eventInScope = function(charID)
return (charID == self.charID);
end;
end
for _, s in pairs(self.settings.events) do
local event = self:CreateEvent(s, true);
if (event) then
self.events[event] = s;
end
end
self.table:ReSort();
end
function Tab:CreateEvent(settings, moreEvents)
if (not self.eventInScope(settings.charID)) then
return;
end
local event = Event(self, settings);
if (event:IsExpired()) then
self.window:AddAlert(event, true);
end
AddCallback(event, "ExpiredChanged", function(e, args)
self:ExpiredChanged(e, args);
end);
local row, cells = self.table:AddRow(event, moreEvents);
event:SetCells(cells);
-- Display various clicky icons, when mouse is present
AddCallback(row, "MouseEnter", function(ctl)
self:ShowXIcon(ctl, 1, 1, event);
if ((self.table:GetColumnWeight("desc") > 0) and event:GetLastAutomaticUpdate()) then
local cell = cells.desc;
self:ShowSettingsIcon(ctl, cell:GetLeft() + cell:GetWidth() - 23, 1, event);
end
if ((self.table:GetColumnWeight("remaining") > 0) and (not self.table:IsColumnLocked("remaining"))) then
local cell = cells.remaining;
self:ShowResetIcon(ctl, cell:GetLeft() + cell:GetWidth() - 23, 1, event);
end
if (self.table:GetColumnWeight("location") > 0) then
local cell = cells.location;
if (not self.table:IsColumnLocked("location")) then
self:ShowTargetIcon(ctl, cell:GetLeft() + cell:GetWidth() - 23, 1, event);
end
self:ShowWaypointIcon(ctl, cell:GetLeft() + 1, 1, event);
end
-- Turn off shimmering
if (ctl.shimmer) then
ctl.shimmer = nil;
for c = 1, #ctl.cells do
self.window.shimmering:Remove(ctl.cells[c]);
end
end
end);
AddCallback(row, "MouseLeave", function(ctl)
if (not (self.x_icon:IsMouseOver() or self.settings_icon:IsMouseOver() or self.reset_icon:IsMouseOver() or self.target_icon:IsMouseOver() or self.waypoint_icon:IsMouseOver())) then
self.x_icon:SetVisible(false);
self.settings_icon:SetVisible(false);
self.reset_icon:SetVisible(false);
self.waypoint_icon:SetVisible(false);
self.target_icon:SetVisible(false);
end
end);
row.ContextMenu = function()
self:ShowEventContextMenu(event);
end
if (not moreEvents) then
self:ReapplySort(nil, true);
end
return event;
end
function Tab:EnsureEventVisible(event)
self.table:EnsureVisible(event);
self.table:GetRow(event):Focus();
end
function Tab:SelectEvent(event)
if (event) then
self:EnsureEventVisible(event);
end
self.table:SelectRow(event);
end
-- Called once after settings are loaded, to change the time of any of the
-- current character's "at next login" events to "now"
function Tab:Login()
local gameTime = Turbine.Engine.GetGameTime();
for event, _ in pairs(self.events) do
if ((event:GetExpirationTime() == 0) and event:IsMine()) then
event:SetExpirationTime(gameTime);
self:SaveSettings();
end
end
self:ReapplySort("remaining");
end
function Tab:DeleteEvent(event)
self.window:RemoveAlert(event);
self.table:DeleteRow(event);
local settings = self.events[event];
self.events[event] = nil;
for n, s in pairs(self.settings.events) do
if (s == settings) then
self.settings.events[n] = nil;
break;
end
end
event:Destroy();
self:SaveSettings();
end
function Tab:Close()
for event, _ in pairs(self.events) do
event:Destroy();
end
Turbine.UI.Window.Close(self);
end
function Tab:SaveSettings(now)
self.window:SaveSettings(now);
end
-- Function must accept a single 'event' argument.
-- Returning nil will continue the loop.
-- Returning 'true' aborts the loop and returns the event object.
function Tab:ForEachEventDo(func)
for event, _ in pairs(self.events) do
if (func(event)) then
return event;
end
end
end
function Tab:UpdateDistanceColumn(location)
local x1, y1 = Event.GetCoords(location or "");
local unknown = "â";
self:ForEachEventDo(function(event)
local distCell = event.cells["distance"];
if (x1 and y1) then
local x2, y2 = event.cells["location"].x, event.cells["location"].y;
if (x2 and y2) then
distCell.sortValue = ((x1 - x2)^2 + (y1 - y2)^2)^0.5 * 202.2171; -- ratio from Lunarwater
distCell:SetText(string.format("%.1d", math.ceil(distCell.sortValue)) .. "m");
else
distCell.sortValue = math.huge;
distCell:SetText(unknown);
end
else
distCell.sortValue = math.huge;
distCell:SetText(unknown);
end
end);
self:ReapplySort("distance");
end
function Tab:ExpiredChanged(event, expired)
if (expired) then
local controls = {};
-- Make the event shimmer in the table
local cells = event:GetCells();
cells["desc"]:GetParent().shimmer = true;
for colName, cell in pairs(cells) do
table.insert(controls, cell);
end
-- If the tab is not in front, make the tab shimmer as well
if (not self:IsInFront()) then
table.insert(controls, self.tabText);
end
self.window:AddShimmer(controls);
self.window:AddAlert(event);
else
self.window:RemoveAlert(event);
end
end
function Tab:CleanupDropDowns()
if (self.dropDownCtl) then
self.dropDownCtl.dropDown:SetParent(nil); -- Could trigger the mouse wheel bug, since it's a descendent of a ListBox. But currently it seems to work OK.
self.dropDownCtl.dropDown = nil;
self.dropDownCtl:SetWantsKeyEvents(false);
self.dropDownCtl = nil;
end
end
function Tab:Deselect()
self.table:Deselect()
end
function Tab:SelectionChanged(args)
self:CleanupDropDowns();
if (args.Old) then
args.Old:SelectionLost();
end
if (args.New) then
args.New:SelectionGained();
end
self.selectedEvent = args.New;
end
function Tab:GetSelectedEvent()
return self.selectedEvent;
end
-- Resorts the table if and only if it's sorted on the specified column
function Tab:ReapplySort(columnName, now)
if ((columnName == nil) or self.table:IsSorted(columnName)) then
self.table:ReSort(now);
end
end
function Tab:IsColumnShowing(columnName)
return (self.table:GetColumnWeight(columnName) > 0);
end
-- Returns true if the tab is currently displaying any events (according to current scope)
function Tab:IsEmpty()
return not next(self.events);
end