You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
8.1 KiB
325 lines
8.1 KiB
|
|
-- Sort lib
|
|
local _, app = ...;
|
|
|
|
-- Concepts:
|
|
-- Encapsulates the functionality for performing sort logic against sets of ATT groups
|
|
|
|
-- Global locals
|
|
local ipairs, pairs, tostring, type, string_lower, table_sort, pcall
|
|
= ipairs, pairs, tostring, type, string.lower, table.sort, pcall;
|
|
|
|
-- App locals
|
|
|
|
-- Module locals
|
|
|
|
-- Sorting Logic
|
|
local calculateAccessibility = function(source)
|
|
local score = 0;
|
|
if source.nmr then
|
|
score = score + 10;
|
|
end
|
|
if source.nmc then
|
|
score = score + 10;
|
|
end
|
|
if source.e then
|
|
score = score + 1;
|
|
end
|
|
if source.u then
|
|
score = score + 1;
|
|
if source.u < 3 then
|
|
score = score + 100;
|
|
elseif source.u < 4 then
|
|
score = score + 10;
|
|
else
|
|
score = score + 1;
|
|
end
|
|
end
|
|
return score;
|
|
end
|
|
local sortByAccessibility = function(a, b)
|
|
return calculateAccessibility(a) <= calculateAccessibility(b);
|
|
end
|
|
local defaultComparison = function(a,b)
|
|
-- If either object doesn't exist
|
|
if a then
|
|
if not b then
|
|
return true;
|
|
end
|
|
elseif b then
|
|
return false;
|
|
else
|
|
-- neither a or b exists, equality returns false
|
|
return false;
|
|
end
|
|
-- If comparing non-tables
|
|
if type(a) ~= "table" or type(b) ~= "table" then
|
|
return a < b;
|
|
end
|
|
local acomp, bcomp;
|
|
-- Maps
|
|
acomp = a.mapID;
|
|
bcomp = b.mapID;
|
|
if acomp then
|
|
if not bcomp then return true; end
|
|
elseif bcomp then
|
|
return false;
|
|
end
|
|
-- Raids/Encounter
|
|
acomp = a.isRaid;
|
|
bcomp = b.isRaid;
|
|
if acomp then
|
|
if not bcomp then return true; end
|
|
elseif bcomp then
|
|
return false;
|
|
end
|
|
-- Headers/Filters
|
|
acomp = a.headerID or a.filterID;
|
|
bcomp = b.headerID or b.filterID;
|
|
if acomp then
|
|
if not bcomp then return true; end
|
|
elseif bcomp then
|
|
return false;
|
|
end
|
|
-- Quests
|
|
acomp = a.questID;
|
|
bcomp = b.questID;
|
|
if acomp then
|
|
if not bcomp then return true; end
|
|
elseif bcomp then
|
|
return false;
|
|
end
|
|
-- Items
|
|
acomp = a.itemID;
|
|
bcomp = b.itemID;
|
|
if acomp then
|
|
if not bcomp then return true; end
|
|
elseif bcomp then
|
|
return false;
|
|
end
|
|
-- Any two similar-type groups via name
|
|
acomp = string_lower(tostring(a.name));
|
|
bcomp = string_lower(tostring(b.name));
|
|
return acomp < bcomp;
|
|
end
|
|
local defaultTextComparison = function(a,b)
|
|
-- If either object doesn't exist
|
|
if a then
|
|
if not b then
|
|
return true;
|
|
end
|
|
elseif b then
|
|
return false;
|
|
else
|
|
-- neither a or b exists, equality returns false
|
|
return false;
|
|
end
|
|
-- Any two similar-type groups with text
|
|
a = string_lower(tostring(a));
|
|
b = string_lower(tostring(b));
|
|
return a < b;
|
|
end
|
|
local defaultNameComparison = function(a,b)
|
|
-- If either object doesn't exist
|
|
if a then
|
|
if not b then
|
|
return true;
|
|
end
|
|
elseif b then
|
|
return false;
|
|
else
|
|
-- neither a or b exists, equality returns false
|
|
return false;
|
|
end
|
|
-- Any two similar-type groups with text
|
|
a = string_lower(tostring(a.name));
|
|
b = string_lower(tostring(b.name));
|
|
return a < b;
|
|
end
|
|
local defaultValueComparison = function(a,b)
|
|
-- If either object doesn't exist
|
|
if a then
|
|
if not b then
|
|
return true;
|
|
end
|
|
elseif b then
|
|
return false;
|
|
else
|
|
-- neither a or b exists, equality returns false
|
|
return false;
|
|
end
|
|
return a < b;
|
|
end
|
|
local defaultHierarchyComparison = function(a,b)
|
|
-- If either object doesn't exist
|
|
if a then
|
|
if not b then
|
|
return true;
|
|
end
|
|
elseif b then
|
|
return false;
|
|
else
|
|
-- neither a or b exists, equality returns false
|
|
return false;
|
|
end
|
|
local acomp, bcomp;
|
|
acomp = a.g and #a.g or 0;
|
|
bcomp = b.g and #b.g or 0;
|
|
return acomp < bcomp;
|
|
end
|
|
local defaultTotalComparison = function(a,b)
|
|
-- If either object doesn't exist
|
|
if a then
|
|
if not b then
|
|
return true;
|
|
end
|
|
elseif b then
|
|
return false;
|
|
else
|
|
-- neither a or b exists, equality returns false
|
|
return false;
|
|
end
|
|
local acomp, bcomp;
|
|
acomp = a.total or 0;
|
|
bcomp = b.total or 0;
|
|
return acomp < bcomp;
|
|
end
|
|
local defaultEventStartComparison = function(a,b)
|
|
-- If either object doesn't exist
|
|
if a then
|
|
if not b then
|
|
return true;
|
|
end
|
|
elseif b then
|
|
return false;
|
|
else
|
|
-- neither a or b exists, equality returns false
|
|
return false;
|
|
end
|
|
local acomp, bcomp;
|
|
acomp = a.nextEvent;
|
|
acomp = acomp and acomp.start or 0;
|
|
bcomp = b.nextEvent;
|
|
bcomp = bcomp and bcomp.start or 0;
|
|
return acomp < bcomp;
|
|
end
|
|
app.SortDefaults = {
|
|
Accessibility = sortByAccessibility,
|
|
Global = defaultComparison,
|
|
Text = defaultTextComparison,
|
|
Name = defaultNameComparison,
|
|
Value = defaultValueComparison,
|
|
-- Sorts objects first by whether they do not have sub-groups [.g] defined
|
|
Hierarchy = defaultHierarchyComparison,
|
|
-- Sorts objects first by how many total collectibles they contain
|
|
Total = defaultTotalComparison,
|
|
-- Sorts objects first by their nextEvent.Start
|
|
EventStart = defaultEventStartComparison,
|
|
};
|
|
local function Sort(t, compare, nested)
|
|
if t then
|
|
if not compare then compare = defaultComparison; end
|
|
table_sort(t, compare);
|
|
if nested then
|
|
for i=#t,1,-1 do
|
|
Sort(t[i].g, compare, nested);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- Safely-sorts a table using a provided comparison function and whether to propogate to nested groups
|
|
-- Wrapping in a pcall since sometimes the sorted values are able to change while being within the sort method. This causes the 'invalid sort order function' error
|
|
app.Sort = function(t, compare, nested)
|
|
pcall(Sort, t, compare, nested);
|
|
end
|
|
local function GetGroupSortValue(group)
|
|
-- sub-groups on top
|
|
-- >= 1
|
|
if group.g then
|
|
local total = group.total;
|
|
if total then
|
|
local progress = group.progress;
|
|
-- completed groups at the very top, ordered by their own total
|
|
if total == progress then
|
|
-- 3 <= p
|
|
return 2 + total;
|
|
-- partially completed next
|
|
elseif progress and progress > 0 then
|
|
-- 1 < p <= 2
|
|
return 1 + (progress / total);
|
|
-- no completion, ordered by their own total in reverse
|
|
-- 0 < p <= 1
|
|
else
|
|
return (1 / total);
|
|
end
|
|
end
|
|
-- collectibles next
|
|
-- >= 0
|
|
elseif group.collectible then
|
|
-- = 0.5
|
|
if group.collected then
|
|
return 0.5;
|
|
else
|
|
-- 0 <= p < 0.5
|
|
return (group.sortProgress or 0) / 2;
|
|
end
|
|
-- trackables next
|
|
-- -1 <= p <= -0.5
|
|
elseif group.trackable then
|
|
if group.saved then
|
|
return -0.5;
|
|
else
|
|
return -1;
|
|
end
|
|
-- remaining last
|
|
-- = -2
|
|
else
|
|
return -2;
|
|
end
|
|
end
|
|
-- Sorts a group using the provided sortType, whether to recurse through nested groups, and whether sorting should only take place given the group having a conditional field
|
|
local function SortGroup(group, sortType, row, recur, conditionField)
|
|
if group.g then
|
|
-- either sort visible groups or by conditional
|
|
if (not conditionField and group.visible) or (conditionField and group[conditionField]) then
|
|
-- app.PrintDebug("sorting",group.key,group.key and group[group.key],"by",sortType,"recur",recur,"condition",conditionField)
|
|
if sortType == "name" then
|
|
app.Sort(group.g);
|
|
elseif sortType == "progress" then
|
|
local progA, progB;
|
|
app.Sort(group.g, function(a, b)
|
|
progA = GetGroupSortValue(a);
|
|
progB = GetGroupSortValue(b);
|
|
return progA > progB;
|
|
end);
|
|
else
|
|
local sortA, sortB;
|
|
local sortFunc = app.SortDefaults[sortType] or
|
|
(sortType and function(a, b)
|
|
sortA = a and tostring(a[sortType]);
|
|
sortB = b and tostring(b[sortType]);
|
|
return sortA < sortB;
|
|
end) or nil;
|
|
app.Sort(group.g, sortFunc);
|
|
end
|
|
-- since this group was sorted, clear any SortInfo which may have caused it
|
|
group.SortInfo = nil;
|
|
end
|
|
-- TODO: Add more sort types?
|
|
if recur then
|
|
for _,o in ipairs(group.g) do
|
|
SortGroup(o, sortType, nil, recur, conditionField);
|
|
end
|
|
end
|
|
end
|
|
if row then
|
|
row:GetParent():GetParent():Update();
|
|
app.print("Finished Sorting.");
|
|
end
|
|
end
|
|
app.SortGroup = SortGroup;
|
|
-- Allows defining SortGroup data which is only executed when the group is actually expanded
|
|
app.SortGroupDelayed = function(group, sortType, row, recur, conditionField)
|
|
-- app.PrintDebug("Delayed Sort defined for",group.text)
|
|
group.SortInfo = { sortType, row, recur, conditionField };
|
|
end
|