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.
1486 lines
54 KiB
1486 lines
54 KiB
local _, S = ...
|
|
local pairs, ipairs, string, type, time = pairs, ipairs, string, type, time
|
|
|
|
local COLUMN_HEADING_HEIGHT = 24
|
|
|
|
local function GetSortArrow(ascending)
|
|
local s = "|TInterface\\Addons\\Sorted\\Textures\\Sort-Arrow"
|
|
if S.Settings.Get("fontOutline") > 0 then
|
|
s = s.."-Outline"
|
|
if S.Settings.Get("fontOutline") > 1 then
|
|
s = s..":0:0:-5"
|
|
else
|
|
s = s..":0:0:-2"
|
|
end
|
|
else
|
|
s = s..":0:0:-1"
|
|
end
|
|
if not ascending then
|
|
s = s..":-1:16:16:0:16:0:16|t"
|
|
else
|
|
s = s..":0:16:16:0:16:16:0|t"
|
|
end
|
|
return s
|
|
end
|
|
|
|
local function GetSortMethod(self)
|
|
local columnSettings = self:GetColumnSettings()
|
|
return self.columns[columnSettings["selectedColumn"]].sortMethods[columnSettings["sortMethod"]], columnSettings["sortAsc"]
|
|
end
|
|
|
|
local function FilterEntries(self)
|
|
return
|
|
end
|
|
|
|
-- God I wish I had better names for these functions, but here goes...
|
|
-- EntryHasData returns true when the entry refers to an object that exists
|
|
-- For example, a currency with 0 quantity, or an empty item slot in a bag, should return false
|
|
local function EntryHasData(self, entry)
|
|
return true
|
|
end
|
|
-- GetDataForEntry returns the data referenced by the entry
|
|
-- For example, an item entry doesn't store all the data about an item, but has the attributes 'bag' and 'slot'
|
|
-- This function should pass those attributes to S.Data.GetItem to get the actual data
|
|
local function GetDataForEntry(self, entry)
|
|
return {}
|
|
end
|
|
|
|
-- For each entry in .entryData, adds attributes:
|
|
-- .data referencing the data from GetDataForEntry
|
|
-- .hasData, a boolean indicating whether the entry should be displayed
|
|
local function UpdateEntryData(self)
|
|
for k,v in pairs(self.entryData) do
|
|
v.data = self:GetDataForEntry(v)
|
|
v.hasData = self:EntryHasData(v)
|
|
end
|
|
end
|
|
|
|
-- Creates a table which can be iterated through in order to produce the displayed list
|
|
-- Copied from .entryData, but also:
|
|
-- Is sorted
|
|
-- Includes group headings
|
|
-- Doesn't include empty item slots
|
|
-- Filters items
|
|
-- Combine item stacks
|
|
local function UpdateDisplayedEntryData(self)
|
|
local entryDataTable = self.entryData
|
|
|
|
-- Reset entry data
|
|
for k,v in pairs(self.entryData) do
|
|
v.isCombined = nil
|
|
v.otherLocations = nil
|
|
end
|
|
for k,v in pairs(self.entryButtons) do
|
|
v.isCombined = nil
|
|
v.otherLocations = nil
|
|
end
|
|
|
|
-- Load up each entry with its data
|
|
self:UpdateEntryData()
|
|
|
|
-- Filter items
|
|
if self.FilterEntries then
|
|
self:FilterEntries()
|
|
end
|
|
|
|
-- Combine stacks in a new entryDataTable
|
|
-- Makes a table 'items' which is indexed by item key
|
|
-- Then adds them to entryDataTable indexed by number
|
|
local doCombineStacks = self.canCombineStacks and S.Settings.Get("combineStacks") == 1
|
|
if doCombineStacks then
|
|
entryDataTable = {}
|
|
local items = {}
|
|
for _, entry in pairs(self.entryData) do
|
|
if entry.hasData then
|
|
local key = entry.data.key
|
|
if items[key] then
|
|
-- Combine entry with the existing entry
|
|
items[key].count = items[key].count + entry.data.count
|
|
items[key].isCombined = true
|
|
if not items[key].otherLocations then
|
|
items[key].otherLocations = {}
|
|
end
|
|
local t = {}
|
|
for k,v in pairs(entry) do
|
|
t[k] = v
|
|
end
|
|
t.isCombined = false
|
|
t.count = t.data.count
|
|
table.insert(items[key].otherLocations, t)
|
|
else
|
|
local t = {}
|
|
for k,v in pairs(entry) do
|
|
t[k] = v
|
|
end
|
|
t.count = entry.data.count
|
|
t.isCombined = false
|
|
items[key] = t
|
|
end
|
|
end
|
|
end
|
|
local i = 1
|
|
for _, item in pairs(items) do
|
|
entryDataTable[i] = item
|
|
i = i + 1
|
|
end
|
|
else
|
|
for _, entry in pairs(self.entryData) do
|
|
entry.count = entry.data.count
|
|
end
|
|
end
|
|
|
|
-- Sort .entryData
|
|
self:SortTable(entryDataTable)
|
|
|
|
--Insert extra entries from combined stacks that the user has expanded
|
|
if doCombineStacks then
|
|
local i = 1
|
|
while i < #entryDataTable do
|
|
local entry = entryDataTable[i]
|
|
if entry.isCombined then
|
|
if self.expandedCombinedItems[entry.data.key] then
|
|
entry.count = entry.data.count
|
|
for k,v in pairs(entry.otherLocations) do
|
|
i = i + 1
|
|
table.insert(entryDataTable, i, v)
|
|
end
|
|
end
|
|
end
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
-- Create .displayedEntryData
|
|
self.displayedEntryData = {}
|
|
|
|
-- Iterate over entryData and build displayedEntryData
|
|
-- i is the current index of entryData
|
|
-- j is the current index of displayedEntryData
|
|
local i,j = 1,1
|
|
local grouping = self:GetGrouping()
|
|
local heading, headingCollapsed, foundFilteredItem = nil, nil, nil
|
|
local groupName = nil
|
|
local entryData = nil
|
|
|
|
while i <= #entryDataTable do
|
|
entryData = entryDataTable[i]
|
|
|
|
if not entryData.hasData then
|
|
i = i + 1
|
|
|
|
elseif grouping then
|
|
groupName = self.groups[grouping].func(entryData.data)
|
|
|
|
-- Add a new group heading if this entry is in a new group
|
|
-- Don't add a heading for greyed out, filtered items at the bottom of the list
|
|
if not entryData.filtered and not entryData.isNew and heading ~= groupName then
|
|
|
|
if self.gridView then
|
|
-- Get to the next row
|
|
while j % self.numEntriesAcross ~= 1 do
|
|
self.displayedEntryData[j] = {
|
|
["isEmpty"] = true
|
|
}
|
|
j = j + 1
|
|
end
|
|
end
|
|
|
|
self.displayedEntryData[j] = {
|
|
["isGroupHeading"] = true,
|
|
["group"] = groupName
|
|
}
|
|
heading = groupName
|
|
headingCollapsed = self:GetGroupHeadingCollapsed(groupName)
|
|
j = j + 1
|
|
|
|
if self.gridView then
|
|
-- Get to the next row
|
|
while j % self.numEntriesAcross ~= 1 do
|
|
self.displayedEntryData[j] = {
|
|
["isEmpty"] = true
|
|
}
|
|
j = j + 1
|
|
end
|
|
end
|
|
|
|
else
|
|
if not headingCollapsed then
|
|
-- Add a line break before greyed out filtered items
|
|
if not foundFilteredItem and entryData.filtered then
|
|
foundFilteredItem = true
|
|
if self.gridView then
|
|
-- Get to the next row
|
|
while j % self.numEntriesAcross ~= 1 do
|
|
self.displayedEntryData[j] = {
|
|
["isEmpty"] = true
|
|
}
|
|
j = j + 1
|
|
end
|
|
end
|
|
end
|
|
self.displayedEntryData[j] = entryData
|
|
j = j + 1
|
|
end
|
|
i = i + 1
|
|
end
|
|
else
|
|
self.displayedEntryData[j] = entryData
|
|
i = i + 1
|
|
j = j + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local sortingArgs = {}
|
|
local function SortFunction(entry1, entry2)
|
|
if not entry1.hasData then
|
|
return false
|
|
elseif not entry2.hasData then
|
|
return true
|
|
end
|
|
if entry1.filtered and not entry2.filtered then
|
|
return false
|
|
elseif not entry1.filtered and entry2.filtered then
|
|
return true
|
|
end
|
|
if sortingArgs.pinNew then
|
|
if entry1.isNew ~= entry2.isNew then
|
|
return entry1.isNew == true
|
|
end
|
|
end
|
|
if sortingArgs.grouping and not entry1.filtered then
|
|
if entry1.group ~= entry2.group then
|
|
return entry1.group < entry2.group
|
|
end
|
|
end
|
|
if sortingArgs.favoriting then
|
|
if entry1.favorited ~= entry2.favorited then
|
|
if not entry1.favorited then return false elseif not entry2.favorited then return true end
|
|
return entry1.favorited < entry2.favorited
|
|
end
|
|
end
|
|
local result = sortingArgs.sortMethod.func(sortingArgs.asc, entry1.data, entry2.data)
|
|
return result
|
|
end
|
|
|
|
-- Sorts table 't' using SortFunction
|
|
local function SortTable(self, t)
|
|
-- Load up the sortingArgs table
|
|
sortingArgs.grouping = self:GetGrouping()
|
|
sortingArgs.favoriting = self:GetColumnSettings().favoritesOnTop
|
|
sortingArgs.sortMethod, sortingArgs.asc = self:GetSortMethod()
|
|
sortingArgs.pinNew = S.Settings.Get("newOnTop") == 1
|
|
-- Add grouping and favoriting information
|
|
for k,v in pairs(t) do
|
|
if sortingArgs.grouping then
|
|
_, v.group = self.groups[sortingArgs.grouping].func(v.data)
|
|
end
|
|
if sortingArgs.favoriting then
|
|
v.favorited = self:GetEntryFavorited(v.data)
|
|
end
|
|
if sortingArgs.pinNew then
|
|
v.isNew = self:GetEntryNew(v.data)
|
|
end
|
|
end
|
|
table.sort(t, SortFunction)
|
|
end
|
|
|
|
local function AddEntry(self, listEntry)
|
|
table.insert(self.entryData, listEntry)
|
|
end
|
|
|
|
local function EntryExists(self, entryDataIndex)
|
|
if self.entryData[entryDataIndex] and self:EntryHasData(self.entryData[entryDataIndex]) then
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
--[[
|
|
-- Make sure to only run UpdateGroups after sorting!
|
|
local function UpdateGroups(self)
|
|
self.groupHeadings = {}
|
|
self.entriesWithGroupHeadings = {}
|
|
local grouping = self:GetGrouping()
|
|
local currentGroup = nil
|
|
-- i iterates through the original entryData table
|
|
-- j counts the number of entries in the new table, which includes group headings
|
|
local i, j = 1, 1
|
|
while i <= #self.entryData do
|
|
local entry = self.entryData[i]
|
|
local groupName, _ = self.groups[grouping].func(self:GetDataForEntry(entry))
|
|
|
|
if not self:EntryHasData(entry) then
|
|
i = i + 1
|
|
elseif entry.filtered then
|
|
self.entriesWithGroupHeadings[j] = entry
|
|
j = j + 1
|
|
i = i + 1
|
|
elseif currentGroup ~= groupName then
|
|
self.groupHeadings[#self.groupHeadings + 1] = groupName
|
|
self.entriesWithGroupHeadings[j] = {
|
|
["isGroupHeading"] = true,
|
|
["group"] = groupName,
|
|
["groupHeadingIndex"] = j
|
|
}
|
|
j = j + 1
|
|
currentGroup = groupName
|
|
else
|
|
entry.group = groupName
|
|
if not self:GetGroupHeadingCollapsed(groupName) then
|
|
self.entriesWithGroupHeadings[j] = entry
|
|
j = j + 1
|
|
end
|
|
i = i + 1
|
|
end
|
|
end
|
|
end
|
|
local function UpdateGroupsGrid(self)
|
|
self.groupHeadings = {}
|
|
self.entriesWithGroupHeadings = {}
|
|
local grouping = self:GetGrouping()
|
|
local currentGroup = nil
|
|
local foundFilteredItem = false
|
|
-- i iterates through the original entryData table
|
|
-- j counts the number of entries in the new table, which includes group headings
|
|
local i, j = 1, 1
|
|
while i <= #self.entryData do
|
|
local entry = self.entryData[i]
|
|
local groupName, _ = self.groups[grouping].func(self:GetDataForEntry(entry))
|
|
|
|
if not self:EntryHasData(entry) then
|
|
i = i + 1
|
|
elseif entry.filtered then
|
|
if not foundFilteredItem then
|
|
foundFilteredItem = true
|
|
while j % self.numEntriesAcross ~= 1 do
|
|
self.entriesWithGroupHeadings[j] = {
|
|
["empty"] = true
|
|
}
|
|
j = j + 1
|
|
end
|
|
end
|
|
self.entriesWithGroupHeadings[j] = entry
|
|
j = j + 1
|
|
i = i + 1
|
|
elseif currentGroup ~= groupName then
|
|
while j % self.numEntriesAcross ~= 1 do
|
|
self.entriesWithGroupHeadings[j] = {
|
|
["empty"] = true
|
|
}
|
|
j = j + 1
|
|
end
|
|
self.groupHeadings[#self.groupHeadings + 1] = groupName
|
|
self.entriesWithGroupHeadings[j] = {
|
|
["isGroupHeading"] = true,
|
|
["group"] = groupName,
|
|
["groupHeadingIndex"] = math.floor(j / self.numEntriesAcross) + 1
|
|
}
|
|
j = j + 1
|
|
while j % self.numEntriesAcross ~= 1 do
|
|
self.entriesWithGroupHeadings[j] = {
|
|
["empty"] = true
|
|
}
|
|
j = j + 1
|
|
end
|
|
currentGroup = groupName
|
|
else
|
|
entry.group = groupName
|
|
if not self:GetGroupHeadingCollapsed(groupName) then
|
|
self.entriesWithGroupHeadings[j] = entry
|
|
j = j + 1
|
|
end
|
|
i = i + 1
|
|
end
|
|
end
|
|
end
|
|
local function UpdateEntryButtonsWithGrouping(self)
|
|
|
|
UpdateGroups(self)
|
|
|
|
local isAvailable = self:IsAvailable()
|
|
local topEntryIndex = floor(self.scrollPos)
|
|
local i = 1
|
|
while i <= self:GetNumVisibleEntries() do
|
|
local entryButton = self.entryButtons[i]
|
|
local headingButton = self.headingButtons[i]
|
|
if not self.entriesWithGroupHeadings[topEntryIndex + i] then
|
|
entryButton:Hide()
|
|
headingButton:Hide()
|
|
else
|
|
local entryData = self.entriesWithGroupHeadings[topEntryIndex + i]
|
|
if entryData.empty then
|
|
entryButton:Hide()
|
|
headingButton:Hide()
|
|
elseif entryData.isGroupHeading then
|
|
headingButton.group = entryData.group
|
|
headingButton.nameString:SetText(entryData.group)
|
|
headingButton:Show()
|
|
headingButton:SetCollapsed(self:GetGroupHeadingCollapsed(entryData.group))
|
|
entryButton:Hide()
|
|
elseif entryData and self:EntryHasData(entryData) then
|
|
-- Add keys from the entryData table to the entry object before updating it
|
|
for k,w in pairs(entryData) do
|
|
entryButton[k] = w
|
|
end
|
|
entryButton:Show()
|
|
entryButton:Update()
|
|
if isAvailable then
|
|
--entryButton:SetAlpha(1)
|
|
entryButton:Enable()
|
|
else
|
|
--entryButton:SetAlpha(0.8)
|
|
entryButton:Disable()
|
|
end
|
|
headingButton:Hide()
|
|
else
|
|
entryButton:Hide()
|
|
headingButton:Hide()
|
|
end
|
|
end
|
|
i = i + 1
|
|
end
|
|
end
|
|
local function UpdateEntryButtonsWithGroupingGrid(self)
|
|
UpdateGroupsGrid(self)
|
|
local isAvailable = self:IsAvailable()
|
|
local topEntryIndex = floor(self.scrollPos) * self.numEntriesAcross
|
|
for k,v in pairs(self.headingButtons) do
|
|
v:Hide()
|
|
end
|
|
local i = 1
|
|
while i <= self:GetNumVisibleEntries() do
|
|
local entryButton = self.entryButtons[i]
|
|
if not self.entriesWithGroupHeadings[topEntryIndex + i] then
|
|
entryButton:Hide()
|
|
else
|
|
local entryData = self.entriesWithGroupHeadings[topEntryIndex + i]
|
|
if entryData.empty then
|
|
entryButton:Hide()
|
|
elseif entryData.isGroupHeading then
|
|
local headingButton = self.headingButtons[entryData.groupHeadingIndex - floor(self.scrollPos)]
|
|
if headingButton then
|
|
headingButton.group = entryData.group
|
|
headingButton.nameString:SetText(entryData.group)
|
|
headingButton:Show()
|
|
headingButton:SetCollapsed(self:GetGroupHeadingCollapsed(entryData.group))
|
|
end
|
|
entryButton:Hide()
|
|
elseif entryData and self:EntryHasData(entryData) then
|
|
-- Add keys from the entryData table to the entry object before updating it
|
|
for k,w in pairs(entryData) do
|
|
entryButton[k] = w
|
|
end
|
|
entryButton:Show()
|
|
entryButton:Update()
|
|
if isAvailable then
|
|
--entryButton:SetAlpha(1)
|
|
entryButton:Enable()
|
|
else
|
|
--entryButton:SetAlpha(0.8)
|
|
entryButton:Disable()
|
|
end
|
|
else
|
|
entryButton:Hide()
|
|
end
|
|
end
|
|
i = i + 1
|
|
end
|
|
end
|
|
local function UpdateEntryButtons(self)
|
|
if self:GetGrouping() then
|
|
if self.gridView then
|
|
UpdateEntryButtonsWithGroupingGrid(self)
|
|
else
|
|
UpdateEntryButtonsWithGrouping(self)
|
|
end
|
|
return
|
|
end
|
|
local isAvailable = self:IsAvailable()
|
|
local entryIndex
|
|
if self.gridView then
|
|
entryIndex = floor(self.scrollPos) * self.numEntriesAcross + 1
|
|
else
|
|
entryIndex = floor(self.scrollPos) + 1
|
|
end
|
|
for i = 1, self:GetNumVisibleEntries() do
|
|
self.headingButtons[i]:Hide()
|
|
local entry = self.entryButtons[i]
|
|
local entryData = self.entryData[entryIndex]
|
|
if entryData and self:EntryHasData(entryData) then
|
|
-- Add keys from the entryData table to the button before updating it
|
|
for k,w in pairs(entryData) do
|
|
entry[k] = w
|
|
end
|
|
entry:Show()
|
|
entry:Update()
|
|
if isAvailable then
|
|
--v:SetAlpha(1)
|
|
entry:Enable()
|
|
else
|
|
--v:SetAlpha(0.8)
|
|
entry:Disable()
|
|
end
|
|
entryIndex = entryIndex + 1
|
|
else
|
|
entry:Hide()
|
|
entryIndex = entryIndex + 1
|
|
end
|
|
end
|
|
end]]
|
|
|
|
local function UpdateEntryButtons(self)
|
|
local isAvailable = self:IsAvailable()
|
|
local eb, ed, hb -- entryButton, entryData, headingButton
|
|
-- Iterate over the tables
|
|
local bi = 1 -- index in entryButtons
|
|
local di -- index in displayedEntryData
|
|
if self.gridView then
|
|
di = floor(self.scrollPos) * self.numEntriesAcross + 1
|
|
else
|
|
di = floor(self.scrollPos) + 1
|
|
end
|
|
|
|
while bi < self:GetNumVisibleEntries() do
|
|
|
|
eb = self.entryButtons[bi]
|
|
if self.gridView then
|
|
hb = self.headingButtons[floor(bi / self.numEntriesAcross) + 1]
|
|
else
|
|
hb = self.headingButtons[bi]
|
|
end
|
|
|
|
if di > #self.displayedEntryData then
|
|
eb:Hide()
|
|
hb:Hide()
|
|
else
|
|
ed = self.displayedEntryData[di]
|
|
|
|
if ed.isEmpty then
|
|
eb:Hide()
|
|
|
|
elseif ed.isGroupHeading then
|
|
eb:Hide()
|
|
-- Display the group heading
|
|
hb.group = ed.group
|
|
hb.nameString:SetText(ed.group)
|
|
hb:SetCollapsed(self:GetGroupHeadingCollapsed(ed.group))
|
|
hb:Show()
|
|
|
|
else
|
|
hb:Hide()
|
|
-- Add keys from the entry data table to the button before updating it
|
|
for k,v in pairs(ed) do
|
|
eb[k] = v
|
|
end
|
|
eb:Show()
|
|
eb:Update()
|
|
eb.button:SetEnabled(isAvailable)
|
|
end
|
|
end
|
|
|
|
bi = bi + 1
|
|
di = di + 1
|
|
end
|
|
while bi <= #self.entryButtons do
|
|
self.entryButtons[bi]:Hide()
|
|
bi = bi + 1
|
|
end
|
|
end
|
|
|
|
local function CreateGroupHeading(list)
|
|
local self = CreateFrame("FRAME", nil, list.listFrame)
|
|
self:ClearAllPoints()
|
|
self.list = list
|
|
self:SetPoint("LEFT")
|
|
self:SetPoint("RIGHT")
|
|
self:SetHeight(20)
|
|
self.nameString = self:CreateFontString(nil, "OVERLAY", "SortedFont")
|
|
self.nameString:SetPoint("LEFT", 28, 0)
|
|
self.nameString:SetTextColor(S.Utils.GetButtonTextColor():GetRGB())
|
|
self.button = CreateFrame("BUTTON", nil, self)
|
|
self.button.parent = self
|
|
self.button:SetAllPoints()
|
|
self.button:SetNormalTexture("Interface\\Addons\\Sorted\\Textures\\Expand-Button")
|
|
self.button:SetHighlightTexture("Interface\\Addons\\Sorted\\Textures\\Close-Button-Highlight")
|
|
self.button:SetPushedTexture("Interface\\Addons\\Sorted\\Textures\\Expand-Button")
|
|
self.button:GetNormalTexture():ClearAllPoints()
|
|
self.button:GetNormalTexture():SetPoint("LEFT", 2, 0)
|
|
self.button:GetNormalTexture():SetSize(22, 22)
|
|
self.button:GetHighlightTexture():ClearAllPoints()
|
|
self.button:GetHighlightTexture():SetPoint("LEFT", 2, 0)
|
|
self.button:GetHighlightTexture():SetSize(22, 22)
|
|
self.button:GetPushedTexture():ClearAllPoints()
|
|
self.button:GetPushedTexture():SetPoint("LEFT", 2, 0)
|
|
self.button:GetPushedTexture():SetSize(22, 22)
|
|
function self:SetCollapsed(collapsed)
|
|
self.collapsed = collapsed
|
|
if collapsed then
|
|
self.button:GetNormalTexture():SetTexCoord(0, 0.375, 0, 0.375)
|
|
self.button:GetPushedTexture():SetTexCoord(0.375, 0.75, 0, 0.375)
|
|
else
|
|
self.button:GetNormalTexture():SetTexCoord(0, 0.375, 0.375, 0.75)
|
|
self.button:GetPushedTexture():SetTexCoord(0.375, 0.75, 0.375, 0.75)
|
|
end
|
|
end
|
|
self.button:SetScript("OnClick", function(self)
|
|
self.parent.list:ToggleGroupHeading(self.parent.group)
|
|
end)
|
|
self:SetCollapsed(false)
|
|
return self
|
|
end
|
|
|
|
local function GetNumVisibleEntries(self)
|
|
return self.numVisibleEntries
|
|
end
|
|
local function OnResize(self)
|
|
local entryHeight = S.Settings.Get("iconSize") + S.Settings.Get("padding") * 2
|
|
local y = 0
|
|
|
|
-- Create entries to fill frame
|
|
local i = 1
|
|
while y < self.listFrame:GetHeight() + entryHeight do
|
|
if not self.entryButtons[i] then
|
|
self.entryButtons[i] = self.CreateEntry(self, self.listFrame)
|
|
self.headingButtons[i] = CreateGroupHeading(self)
|
|
end
|
|
self.entryButtons[i]:SetParent(self.entryButtons[i].parentFrame)
|
|
if not self.entryButtons[i]:IsShown() then
|
|
self.entryButtons[i]:Show()
|
|
self.entryButtons[i]:OnIconChanged()
|
|
end
|
|
y = y + entryHeight
|
|
i = i + 1
|
|
end
|
|
self.numVisibleEntries = i - 1
|
|
-- Hide entries below bottom of frame
|
|
while i <= #self.entryButtons do
|
|
self.entryButtons[i]:Hide()
|
|
self.entryButtons[i]:ClearAllPoints()
|
|
self.entryButtons[i]:SetParent(nil)
|
|
self.headingButtons[i]:Hide()
|
|
i = i + 1
|
|
end
|
|
self:PositionEntryButtons()
|
|
self:UpdateColumns()
|
|
end
|
|
local function OnResizeGrid(self)
|
|
local size = S.Settings.Get("iconSizeGrid") + S.Settings.Get("paddingGrid") * 2
|
|
local x,y = 0,0
|
|
local listWidth = self:GetWidth() - self.scrollBar:GetWidth()
|
|
self.numEntriesAcross = math.floor(listWidth / size)
|
|
|
|
-- Create entries to fill frame
|
|
local i = 1
|
|
while y < self.listFrame:GetHeight() + size do
|
|
if not self.entryButtons[i] then
|
|
self.entryButtons[i] = self.CreateEntry(self, self.listFrame)
|
|
self.headingButtons[i] = CreateGroupHeading(self)
|
|
end
|
|
self.entryButtons[i]:SetParent(self.entryButtons[i].parentFrame)
|
|
if not self.entryButtons[i]:IsShown() then
|
|
self.entryButtons[i]:Show()
|
|
self.entryButtons[i]:OnIconChanged()
|
|
end
|
|
x = x + size
|
|
if x > listWidth - size then
|
|
x = 0
|
|
y = y + size
|
|
end
|
|
i = i + 1
|
|
end
|
|
self.numVisibleEntries = i - 1
|
|
-- Hide entries below bottom of frame
|
|
while i <= #self.entryButtons do
|
|
self.entryButtons[i]:Hide()
|
|
self.entryButtons[i]:ClearAllPoints()
|
|
self.entryButtons[i]:SetParent(nil)
|
|
self.headingButtons[i]:Hide()
|
|
i = i + 1
|
|
end
|
|
self:PositionEntryButtons()
|
|
self:UpdateColumns()
|
|
end
|
|
|
|
local function ScrollToTop(self)
|
|
self.scrollBar:SetValue(0)
|
|
end
|
|
local function UpdateScrollBarMax(self)
|
|
local entryHeight
|
|
if self.gridView then
|
|
entryHeight = S.Settings.Get("iconSizeGrid") + S.Settings.Get("paddingGrid") * 2
|
|
else
|
|
entryHeight = S.Settings.Get("iconSize") + S.Settings.Get("padding") * 2
|
|
end
|
|
local numEntries = #self.displayedEntryData
|
|
local max
|
|
if self.gridView then
|
|
max = (math.floor(numEntries / self.numEntriesAcross) + 2) - self.listFrame:GetHeight() / entryHeight
|
|
else
|
|
max = numEntries - self.listFrame:GetHeight() / entryHeight
|
|
end
|
|
if max > 0 then
|
|
self.scrollBar:SetMinMaxValues(0, max)
|
|
self.scrollBar:Show()
|
|
else
|
|
self.scrollBar:SetMinMaxValues(0, 0)
|
|
self.scrollBar:Hide()
|
|
end
|
|
end
|
|
|
|
local function PositionEntryButtons(self)
|
|
local entryHeight = S.Settings.Get("iconSize") + S.Settings.Get("padding") * 2
|
|
local y = -(self.scrollPos - floor(self.scrollPos)) * entryHeight
|
|
|
|
for i = 1, self:GetNumVisibleEntries() do
|
|
self.entryButtons[i]:SetHeight(entryHeight)
|
|
self.entryButtons[i]:SetPoint("LEFT")
|
|
self.entryButtons[i]:SetPoint("RIGHT")
|
|
self.entryButtons[i]:SetPoint("TOP", self.listFrame, "TOP", 0, -y)
|
|
self.headingButtons[i]:SetHeight(entryHeight)
|
|
self.headingButtons[i]:SetPoint("LEFT")
|
|
self.headingButtons[i]:SetPoint("RIGHT")
|
|
self.headingButtons[i]:SetPoint("TOP", self.listFrame, "TOP", 0, -y)
|
|
y = y + entryHeight
|
|
end
|
|
end
|
|
local function PositionEntryButtonsGrid(self)
|
|
local size = S.Settings.Get("iconSizeGrid") + S.Settings.Get("paddingGrid") * 2
|
|
local x, y = 0, 0
|
|
local scrollOffset = (self.scrollPos - floor(self.scrollPos)) * size
|
|
local listWidth = self:GetWidth() - self.scrollBar:GetWidth()
|
|
for i = 1, #self.headingButtons do
|
|
self.headingButtons[i]:SetHeight(size)
|
|
self.headingButtons[i]:SetPoint("LEFT")
|
|
self.headingButtons[i]:SetPoint("RIGHT")
|
|
self.headingButtons[i]:SetPoint("TOP", self.listFrame, "TOP", 0, -i * size + size + scrollOffset)
|
|
end
|
|
for i = 1, self:GetNumVisibleEntries() do
|
|
self.entryButtons[i]:ClearAllPoints()
|
|
self.entryButtons[i]:SetSize(size, size)
|
|
self.entryButtons[i]:SetPoint("TOPLEFT", x, -y + scrollOffset)
|
|
x = x + size
|
|
if x > listWidth - size then
|
|
x = 0
|
|
y = y + size
|
|
end
|
|
end
|
|
end
|
|
|
|
local function SelectGrouping(self, key)
|
|
self.groupingSettings["selectedGrouping"] = key
|
|
self.groupingSettings["collapsedGroups"] = {}
|
|
S.Utils.TriggerEvent("GroupingChanged")
|
|
end
|
|
local function DeselectGrouping(self)
|
|
self.groupingSettings["selectedGrouping"] = nil
|
|
S.Utils.TriggerEvent("GroupingChanged")
|
|
end
|
|
local function GetGrouping(self)
|
|
return self.groupingSettings["selectedGrouping"]
|
|
end
|
|
local function ToggleGroupHeading(self, group)
|
|
if self.groupingSettings.collapsedGroups[group] then
|
|
self.groupingSettings.collapsedGroups[group] = nil
|
|
else
|
|
self.groupingSettings.collapsedGroups[group] = true
|
|
end
|
|
S.Utils.TriggerEvent("GroupingChanged")
|
|
end
|
|
local function GetGroupHeadingCollapsed(self, group)
|
|
return self.groupingSettings.collapsedGroups[group]
|
|
end
|
|
|
|
local function UpdateColumnsSortArrows(self)
|
|
local cs = self:GetColumnSettings()
|
|
for k,v in pairs(self.columnHeadings) do
|
|
local col = self.columns[k]
|
|
if k == cs.selectedColumn then
|
|
local sortMethod = col.sortMethods[cs.sortMethod]
|
|
if sortMethod.inverse then
|
|
v.nameString:SetText(sortMethod.title..GetSortArrow(not cs.sortAsc))
|
|
else
|
|
v.nameString:SetText(sortMethod.title..GetSortArrow(cs.sortAsc))
|
|
end
|
|
else
|
|
if col.sortMethods then
|
|
v.nameString:SetText(col.sortMethods[1].title)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function PositionColumns(self)
|
|
local nameColumnIndex = 0
|
|
local nameColumnButton = nil
|
|
local doCombineStacks = self.canCombineStacks and S.Settings.Get("combineStacks") == 1
|
|
-- Find the middle 'name' column which expands to fill the remaining space
|
|
for i,v in ipairs(self:GetColumnOrder()) do
|
|
local key = self:GetColumnOrder()[i]
|
|
if key == "NAME" then
|
|
nameColumnIndex = i
|
|
nameColumnButton = self.columnHeadings[v]
|
|
nameColumnButton:SetPoint("TOP")
|
|
nameColumnButton:SetPoint("BOTTOM")
|
|
end
|
|
end
|
|
local lastEnabledColumnButton = nil
|
|
for i = 1, nameColumnIndex - 1, 1 do
|
|
local key = self:GetColumnOrder()[i]
|
|
if self:ColumnEnabled(key) then
|
|
local button = self.columnHeadings[key]
|
|
local column = self.columns[key]
|
|
button:ClearAllPoints()
|
|
button:SetPoint("TOP", self.head)
|
|
button:SetPoint("BOTTOM", self.head)
|
|
|
|
-- Resize handle goes on the right
|
|
if button.resizeButton then
|
|
button.resizeButton:SetPoint("LEFT", button, "RIGHT", -3, 0)
|
|
button.resizeButton.invert = false
|
|
end
|
|
|
|
if lastEnabledColumnButton then
|
|
button:SetPoint("LEFT", lastEnabledColumnButton, "RIGHT")
|
|
else
|
|
if doCombineStacks then
|
|
button:SetPoint("LEFT", self.head, 20, 0)
|
|
else
|
|
button:SetPoint("LEFT", self.head)
|
|
end
|
|
end
|
|
button:SetWidth(column:GetWidth(key))
|
|
lastEnabledColumnButton = button
|
|
end
|
|
end
|
|
if lastEnabledColumnButton then
|
|
nameColumnButton:SetPoint("LEFT", lastEnabledColumnButton, "RIGHT")
|
|
else
|
|
nameColumnButton:SetPoint("LEFT")
|
|
end
|
|
lastEnabledColumnButton = nil
|
|
for i = #self:GetColumnOrder(), nameColumnIndex + 1, -1 do
|
|
local key = self:GetColumnOrder()[i]
|
|
if self:ColumnEnabled(key) then
|
|
local button = self.columnHeadings[key]
|
|
local column = self.columns[key]
|
|
button:ClearAllPoints()
|
|
button:SetPoint("TOP", self.head)
|
|
button:SetPoint("BOTTOM", self.head)
|
|
|
|
-- Resize handle goes on the left
|
|
if button.resizeButton then
|
|
button.resizeButton:SetPoint("LEFT", -3, 0)
|
|
button.resizeButton.invert = true
|
|
end
|
|
|
|
if lastEnabledColumnButton then
|
|
button:SetPoint("RIGHT", lastEnabledColumnButton, "LEFT")
|
|
else
|
|
button:SetPoint("RIGHT", self.head)
|
|
end
|
|
button:SetWidth(column:GetWidth(key))
|
|
lastEnabledColumnButton = button
|
|
end
|
|
end
|
|
if lastEnabledColumnButton then
|
|
nameColumnButton:SetPoint("RIGHT", lastEnabledColumnButton, "LEFT")
|
|
else
|
|
nameColumnButton:SetPoint("RIGHT")
|
|
end
|
|
end
|
|
local function UpdateColumns(self)
|
|
for k,v in pairs(self.columns) do
|
|
if not self.gridView then
|
|
for i = 1, self:GetNumVisibleEntries() do
|
|
local entry = self.entryButtons[i]
|
|
if entry.columnElements[k] then
|
|
entry.columnElements[k]:SetShown(self:ColumnEnabled(k))
|
|
end
|
|
end
|
|
end
|
|
self.columnHeadings[k]:SetShown(self:ColumnEnabled(k))
|
|
end
|
|
if self:GetColumnSettings().favoritesOnTop then
|
|
self.columnHeadings["FAVORITES"].favoriteIcon:SetTexCoord(0, 0.21875, 0, 0.21875)
|
|
else
|
|
self.columnHeadings["FAVORITES"].favoriteIcon:SetTexCoord(0, 0.21875, 0.21875 * 2, 0.21875 * 3)
|
|
end
|
|
self:PositionColumns()
|
|
end
|
|
|
|
|
|
local function EnableColumn(self, columnKey)
|
|
self:GetColumnSettings().enabledColumns[columnKey] = true
|
|
-- Add column to the columnOrder only if it isn't there already
|
|
for i, v in ipairs(self:GetColumnOrder()) do
|
|
if v == columnKey then
|
|
S.Utils.TriggerEvent("MinSizeChanged")
|
|
S.Utils.TriggerEvent("ColumnsChanged")
|
|
return
|
|
end
|
|
end
|
|
table.insert(self:GetColumnOrder(), columnKey)
|
|
S.Utils.TriggerEvent("MinSizeChanged")
|
|
S.Utils.TriggerEvent("ColumnsChanged")
|
|
end
|
|
local function DisableColumn(self, columnKey)
|
|
self:GetColumnSettings().enabledColumns[columnKey] = false
|
|
S.Utils.TriggerEvent("MinSizeChanged")
|
|
S.Utils.TriggerEvent("ColumnsChanged")
|
|
end
|
|
local function ColumnEnabled(self, columnKey)
|
|
return self:GetColumnSettings().enabledColumns[columnKey]
|
|
end
|
|
local function OnDropdownColumnEntryClick(self)
|
|
if self.checked then
|
|
EnableColumn(self.data1, self.data2)
|
|
else
|
|
DisableColumn(self.data1, self.data2)
|
|
end
|
|
end
|
|
local function OnDropdownGroupingEntryClick(self)
|
|
if self.checked then
|
|
SelectGrouping(self.data1, self.data2)
|
|
else
|
|
DeselectGrouping(self.data1, self.data2)
|
|
end
|
|
end
|
|
local function ColumnOnClick(self, button, down)
|
|
-- Don't trigger a click if the column has been dragged around
|
|
if not self.list.movedColumn then
|
|
|
|
if button == "LeftButton" then
|
|
local cs = self.list:GetColumnSettings()
|
|
local col = self.list.columns[self.key]
|
|
if col.sortMethods then
|
|
if cs.selectedColumn == self.key then
|
|
if not cs.sortAsc then
|
|
cs.sortAsc = true
|
|
else
|
|
cs.sortAsc = false
|
|
cs.sortMethod = cs.sortMethod + 1
|
|
if not col.sortMethods[cs.sortMethod] then
|
|
cs.sortMethod = 1
|
|
end
|
|
end
|
|
else
|
|
cs.selectedColumn = self.key
|
|
cs.sortAsc = false
|
|
cs.sortMethod = 1
|
|
end
|
|
S.Utils.TriggerEvent("SortingChanged")
|
|
elseif self.key == "FAVORITES" then
|
|
cs.favoritesOnTop = not cs.favoritesOnTop
|
|
S.Utils.TriggerEvent("SortingChanged")
|
|
S.Utils.TriggerEvent("ColumnsChanged")
|
|
end
|
|
elseif button == "RightButton" then
|
|
-- Dropdown menu
|
|
if S.Dropdown.IsShown() then
|
|
S.Dropdown.Hide()
|
|
else
|
|
S.Dropdown.Reset()
|
|
|
|
S.Dropdown.AddEntry(S.Localize("CONFIG_GROUPING"), nil, nil, nil, S.Utils.GetButtonTextColor())
|
|
local dropdownEntries = {}
|
|
for k,v in pairs(self.list.groups) do
|
|
table.insert(dropdownEntries, {
|
|
["key"] = k,
|
|
["name"] = v.name
|
|
})
|
|
end
|
|
table.sort(dropdownEntries, function(a,b) return a.name < b.name end)
|
|
for i,v in ipairs(dropdownEntries) do
|
|
S.Dropdown.AddEntry(v.name, OnDropdownGroupingEntryClick, self.list, v.key)
|
|
S.Dropdown.AddRadioButton(self.list:GetGrouping() == v.key)
|
|
end
|
|
|
|
S.Dropdown.AddEntry(S.Localize("CONFIG_COLUMNS"), nil, nil, nil, S.Utils.GetButtonTextColor())
|
|
dropdownEntries = {}
|
|
for k,v in pairs(self.list.columns) do
|
|
if v:GetWidth() then -- Don't allow the name column to be disabled. It can be identified because it has no defined width
|
|
local name = v.name
|
|
if v.sortMethods then
|
|
if v.sortMethods[1].title ~= name and #v.sortMethods[1].title > 0 then
|
|
name = name.." ("..v.sortMethods[1].title..")"
|
|
end
|
|
end
|
|
table.insert(dropdownEntries, {
|
|
["key"] = k,
|
|
["name"] = name
|
|
})
|
|
end
|
|
end
|
|
table.sort(dropdownEntries, function(a,b) return a.name < b.name end)
|
|
for i,v in ipairs(dropdownEntries) do
|
|
S.Dropdown.AddEntry(v.name, OnDropdownColumnEntryClick, self.list, v.key)
|
|
S.Dropdown.AddCheckbox(self.list:ColumnEnabled(v.key))
|
|
end
|
|
|
|
local x,y = GetCursorPosition()
|
|
x,y = x/UIParent:GetEffectiveScale(), y/UIParent:GetEffectiveScale()
|
|
S.Dropdown.Show(UIParent, "TOPLEFT", "BOTTOMLEFT", x, y)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function GetColumnSettings(self)
|
|
return S.Settings.Get(self.columnSettingsKey)
|
|
end
|
|
local function GetColumnOrder(self)
|
|
return GetColumnSettings(self).order
|
|
end
|
|
|
|
local function GetEntryFavorited(self, entryData)
|
|
return false
|
|
end
|
|
|
|
local function GetEntryNew(self, entryData)
|
|
return false
|
|
end
|
|
|
|
local function GetMinWidth(self)
|
|
local width = 100 -- Effectively the minimum width of the name column
|
|
for key, col in pairs(self.columns) do
|
|
if self:ColumnEnabled(key) then
|
|
local colWidth = col:GetWidth(key)
|
|
if colWidth then
|
|
width = width + colWidth
|
|
end
|
|
end
|
|
end
|
|
return width
|
|
end
|
|
|
|
local function SetMinimised(self, minimised)
|
|
|
|
end
|
|
|
|
local function IsAvailable(self)
|
|
return S.IsPlayingCharacterSelected()
|
|
end
|
|
|
|
local function ToggleGridView(self)
|
|
self.gridView = not self.gridView
|
|
if self.gridView then
|
|
self.OnResize = OnResizeGrid
|
|
self:OnResize()
|
|
self.PositionEntryButtons = PositionEntryButtonsGrid
|
|
for k,v in pairs(self.entryButtons) do
|
|
v:DetachFramesFromColumns()
|
|
v.columnElements["ICON"]:SetAllPoints()
|
|
v.columnElements["ICON"]:Show()
|
|
v.columnElements["QUANTITY"]:SetParent(v.columnElements["ICON"])
|
|
v.columnElements["QUANTITY"]:SetPoint("BOTTOMRIGHT")
|
|
v.columnElements["QUANTITY"]:SetPoint("TOPLEFT", v, "RIGHT")
|
|
v.columnElements["QUANTITY"]:Show()
|
|
v.button:SetPushedTexture("")
|
|
v:OnIconChanged()
|
|
end
|
|
else
|
|
self.OnResize = OnResize
|
|
self:OnResize()
|
|
self.PositionEntryButtons = PositionEntryButtons
|
|
for k,v in pairs(self.entryButtons) do
|
|
v:ClearAllPoints()
|
|
v:SetPoint("LEFT")
|
|
v:SetPoint("RIGHT")
|
|
v.columnElements["QUANTITY"]:SetParent(v)
|
|
v.columnElements["ICON"]:ClearAllPoints()
|
|
v.columnElements["QUANTITY"]:ClearAllPoints()
|
|
v:AttachFramesToColumns()
|
|
v.button:SetPushedTexture("Interface\\Addons\\Sorted\\Textures\\UI-Highlight")
|
|
v:OnIconChanged()
|
|
if k > self:GetNumVisibleEntries() then
|
|
v:Hide()
|
|
end
|
|
end
|
|
end
|
|
self:PositionEntryButtons()
|
|
self:ScheduleUpdate(false, false)
|
|
S.Utils.TriggerEvent("LayoutChanged")
|
|
end
|
|
|
|
local function CreateColumnButton(self, key)
|
|
local b = CreateFrame("BUTTON", "", self.head)
|
|
b.normalTex = b:CreateTexture(nil, "BACKGROUND")
|
|
b.normalTex:SetTexture("Interface\\Addons\\Sorted\\Textures\\Column-Heading")
|
|
b.normalTex:SetTexCoord(0.2, 0.8, 0, 1)
|
|
b.normalTex:SetPoint("TOPLEFT", 4, 0)
|
|
b.normalTex:SetPoint("BOTTOMRIGHT", -4, 0)
|
|
b.normalTexL = b:CreateTexture(nil, "BACKGROUND")
|
|
b.normalTexL:SetTexture("Interface\\Addons\\Sorted\\Textures\\Column-Heading")
|
|
b.normalTexL:SetTexCoord(0, 0.2, 0, 1)
|
|
b.normalTexL:SetPoint("TOPLEFT")
|
|
b.normalTexL:SetPoint("BOTTOMRIGHT", b, "BOTTOMLEFT", 4, 0)
|
|
b.normalTexR = b:CreateTexture(nil, "BACKGROUND")
|
|
b.normalTexR:SetTexture("Interface\\Addons\\Sorted\\Textures\\Column-Heading")
|
|
b.normalTexR:SetTexCoord(0.8, 1, 0, 1)
|
|
b.normalTexR:SetPoint("TOPLEFT", b, "TOPRIGHT", -4, 0)
|
|
b.normalTexR:SetPoint("BOTTOMRIGHT")
|
|
b:SetHighlightTexture("Interface\\Addons\\Sorted\\Textures\\Column-Heading-Highlight")
|
|
b:SetPushedTexture("Interface\\Addons\\Sorted\\Textures\\Column-Heading-Highlight")
|
|
b.nameString = b:CreateFontString(nil, "OVERLAY", "SortedFont")
|
|
b.nameString:SetPoint("LEFT")
|
|
b.nameString:SetPoint("RIGHT")
|
|
b.nameString:SetHeight(1)
|
|
|
|
if self.columns[key].width then
|
|
b.resizeButton = CreateFrame("BUTTON", "", b)
|
|
b.resizeButton:SetPoint("TOP")
|
|
b.resizeButton:SetPoint("BOTTOM")
|
|
b.resizeButton:SetWidth(6)
|
|
b.resizeButton:SetFrameLevel(b:GetFrameLevel() + 10)
|
|
b.resizeButton:SetHighlightTexture("Interface\\Addons\\Sorted\\Textures\\Close-Button-Highlight")
|
|
b.resizeButton:GetHighlightTexture():SetTexCoord(0, 1, 0.3, 0.7)
|
|
b.resizeButton:SetPushedTexture("Interface\\Addons\\Sorted\\Textures\\Close-Button-Highlight")
|
|
b.resizeButton:GetPushedTexture():SetBlendMode("ADD")
|
|
b.resizeButton:GetPushedTexture():SetTexCoord(0, 1, 0.3, 0.7)
|
|
b.resizeButton.key = key
|
|
b.resizeButton.list = self
|
|
b.resizeButton:SetScript("OnMouseDown", function(self)
|
|
local settings = self.list:GetColumnSettings()
|
|
if not settings.widths then
|
|
settings.widths = {}
|
|
end
|
|
if not settings.widths[self.key] then
|
|
settings.widths[self.key] = self.list.columns[self.key].width
|
|
end
|
|
self.x, self.y = GetCursorPosition()
|
|
self.x = self.x / self:GetEffectiveScale()
|
|
self.y = self.y / self:GetEffectiveScale()
|
|
self.startWidth = settings.widths[self.key]
|
|
|
|
self:SetScript("OnUpdate", function(self)
|
|
local x, y = GetCursorPosition()
|
|
x = x / self:GetEffectiveScale()
|
|
y = y / self:GetEffectiveScale()
|
|
if self.invert then
|
|
settings.widths[self.key] = self.startWidth - (x - self.x)
|
|
else
|
|
settings.widths[self.key] = self.startWidth + (x - self.x)
|
|
end
|
|
if settings.widths[self.key] < 16 then
|
|
settings.widths[self.key] = 16
|
|
end
|
|
self.list:PositionColumns()
|
|
end)
|
|
end)
|
|
b.resizeButton:SetScript("OnMouseUp", function(self)
|
|
self:SetScript("OnUpdate", nil)
|
|
S.primaryFrame:UpdateMinSize()
|
|
S.primaryFrame.sideFrame:UpdateMinSize()
|
|
end)
|
|
end
|
|
|
|
b:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
--b:RegisterForDrag("LeftButton")
|
|
|
|
b.key = key
|
|
b.list = self
|
|
return b
|
|
end
|
|
|
|
local lastUpdateTime = 0
|
|
local function ScheduleUpdate(self, resize, sort)
|
|
self.updateScheduled = true
|
|
self.resizeScheduled = resize
|
|
self.sortingScheduled = sort
|
|
end
|
|
local function OnUpdate(self)
|
|
if self.updateScheduled and GetTime() > lastUpdateTime + 0.1 then
|
|
if self.resizeScheduled then
|
|
self:OnResize()
|
|
end
|
|
self:UpdateColumnsSortArrows()
|
|
self:UpdateColumns()
|
|
if sort then
|
|
self:UpdateDisplayedEntryData()
|
|
--self:Sort()
|
|
end
|
|
self:UpdateEntryButtons()
|
|
self:UpdateScrollBarMax()
|
|
|
|
self.updateScheduled = false
|
|
self.resizeScheduled = false
|
|
self.sortingScheduled = false
|
|
|
|
lastUpdateTime = GetTime()
|
|
end
|
|
end
|
|
|
|
|
|
function S.CreateList(parent, entryConstructor, tColumns, sColumnSettings, bColumnHeadings, tGroups, groupingSettings)
|
|
local self = CreateFrame("SCROLLFRAME", "", parent)
|
|
|
|
self.gridView = false
|
|
self.ToggleGridView = ToggleGridView
|
|
|
|
self.entryButtons = {}
|
|
self.entryData = {}
|
|
self.EntryExists = EntryExists
|
|
self.EntryHasData = EntryHasData
|
|
self.GetDataForEntry = GetDataForEntry
|
|
self.UpdateEntryData = UpdateEntryData
|
|
self.UpdateDisplayedEntryData = UpdateDisplayedEntryData
|
|
self.scrollPos = 0
|
|
self.lastScrollPosInteger = 0
|
|
self.hasColumnHeadings = bColumnHeadings
|
|
self.columns = tColumns
|
|
self.columnSettingsKey = sColumnSettings
|
|
self.ColumnEnabled = ColumnEnabled
|
|
self.GetColumnSettings = GetColumnSettings
|
|
self.GetColumnOrder = GetColumnOrder
|
|
self.UpdateColumns = UpdateColumns
|
|
self.PositionColumns = PositionColumns
|
|
self.AddEntry = AddEntry
|
|
self.ScheduleUpdate = ScheduleUpdate
|
|
self:SetScript("OnUpdate", OnUpdate)
|
|
self.UpdateEntryButtons = UpdateEntryButtons
|
|
self.PositionEntryButtons = PositionEntryButtons
|
|
self.CreateEntry = entryConstructor
|
|
self.OnResize = OnResize
|
|
self.SortTable = SortTable
|
|
self.FilterEntries = FilterEntries
|
|
self.GetSortMethod = GetSortMethod
|
|
self.UpdateColumnsSortArrows = UpdateColumnsSortArrows
|
|
self.UpdateScrollBarMax = UpdateScrollBarMax
|
|
self.ScrollToTop = ScrollToTop
|
|
self.GetMinWidth = GetMinWidth
|
|
self.groups = tGroups
|
|
self.groupHeadings = {}
|
|
self.headingButtons = {}
|
|
self.groupingSettings = groupingSettings
|
|
self.SelectGrouping = SelectGrouping
|
|
self.GetGrouping = GetGrouping
|
|
self.ToggleGroupHeading = ToggleGroupHeading
|
|
self.GetGroupHeadingCollapsed = GetGroupHeadingCollapsed
|
|
self.GetEntryFavorited = GetEntryFavorited
|
|
self.GetEntryNew = GetEntryNew
|
|
self.SetMinimised = SetMinimised
|
|
self.IsAvailable = IsAvailable
|
|
self.GetNumVisibleEntries = GetNumVisibleEntries
|
|
self.numVisibleEntries = 0
|
|
|
|
local f = self
|
|
f:SetAllPoints()
|
|
|
|
f.scrollBar = CreateFrame("SLIDER", "", f, "MinimalScrollBarTemplate")
|
|
f.scrollBar.trackBG:Hide()
|
|
f.scrollBar:SetPoint("BOTTOM", 0, 16)
|
|
f.scrollBar:SetMinMaxValues(0, 200)
|
|
f.scrollBar:SetValue(0)
|
|
f.scrollBar.Update = function(self)
|
|
f.scrollPos = self:GetValue()
|
|
if f.lastScrollPosInteger ~= floor(f.scrollPos) then
|
|
f.lastScrollPosInteger = floor(f.scrollPos)
|
|
f:UpdateEntryButtons()
|
|
end
|
|
f:PositionEntryButtons()
|
|
end
|
|
f.scrollBar:SetScript("OnValueChanged", f.scrollBar.Update)
|
|
f:SetScript("OnMouseWheel", function(self, delta)
|
|
f.scrollBar:SetValue(f.scrollBar:GetValue() - delta * S.Settings.Get("scrollSpeed"))
|
|
f.scrollBar:Update()
|
|
end)
|
|
|
|
f.listFrame = CreateFrame("FRAME", "", self)
|
|
f.listFrame:SetClipsChildren(true)
|
|
f.listFrame:SetPoint("BOTTOM")
|
|
f.listFrame:SetPoint("RIGHT", f.scrollBar, "LEFT", 0, 0)
|
|
if not bColumnHeadings then
|
|
f.listFrame:SetPoint("TOPLEFT", 0, 0)
|
|
f.scrollBar:SetPoint("TOPRIGHT", 0, -18)
|
|
else
|
|
f.listFrame:SetPoint("TOPLEFT", 0, -COLUMN_HEADING_HEIGHT)
|
|
f.scrollBar:SetPoint("TOPRIGHT", 0, -18 - COLUMN_HEADING_HEIGHT)
|
|
f.head = CreateFrame("FRAME", "", f)
|
|
f.head:SetPoint("TOPLEFT")
|
|
f.head:SetPoint("BOTTOM", f, "TOP", 0, -COLUMN_HEADING_HEIGHT)
|
|
f.head:SetPoint("RIGHT", f.scrollBar, "LEFT", 0, 0)
|
|
|
|
f.head.combinedStackSpacer = f.head:CreateTexture("")
|
|
f.head.combinedStackSpacer:SetTexture("Interface\\Addons\\Sorted\\Textures\\Column-Heading-Gap")
|
|
f.head.combinedStackSpacer:SetPoint("TOPLEFT")
|
|
f.head.combinedStackSpacer:SetSize(20, 24)
|
|
|
|
f.head.toggleGridButton = CreateFrame("BUTTON", nil, f.head)
|
|
f.head.toggleGridButton.bg = f.head.toggleGridButton:CreateTexture(nil, "BACKGROUND")
|
|
f.head.toggleGridButton.bg:SetTexture("Interface\\Addons\\Sorted\\Textures\\Column-Heading-Gap")
|
|
f.head.toggleGridButton.bg:SetAllPoints()
|
|
f.head.toggleGridButton:SetPoint("TOPLEFT", f.head, "TOPRIGHT")
|
|
f.head.toggleGridButton:SetSize(f.scrollBar:GetWidth(), COLUMN_HEADING_HEIGHT)
|
|
f.head.toggleGridButton.list = self
|
|
function f.head.toggleGridButton:Update()
|
|
if self.list.gridView then
|
|
self.tooltipText = "TOOLTIP_LAYOUT_LIST"
|
|
self:SetNormalTexture("Interface\\Addons\\Sorted\\Textures\\Layout-List-Up")
|
|
self:SetHighlightTexture("Interface\\Addons\\Sorted\\Textures\\Layout-List-Up")
|
|
self:SetPushedTexture("Interface\\Addons\\Sorted\\Textures\\Layout-List-Down")
|
|
else
|
|
self.tooltipText = "TOOLTIP_LAYOUT_GRID"
|
|
self:SetNormalTexture("Interface\\Addons\\Sorted\\Textures\\Layout-Grid-Up")
|
|
self:SetHighlightTexture("Interface\\Addons\\Sorted\\Textures\\Layout-Grid-Up")
|
|
self:SetPushedTexture("Interface\\Addons\\Sorted\\Textures\\Layout-Grid-Down")
|
|
end
|
|
end
|
|
function f.head.toggleGridButton:UpdatePushed()
|
|
if self.list.gridView then
|
|
self:SetHighlightTexture("Interface\\Addons\\Sorted\\Textures\\Layout-List-Down")
|
|
else
|
|
self:SetHighlightTexture("Interface\\Addons\\Sorted\\Textures\\Layout-Grid-Down")
|
|
end
|
|
end
|
|
f.head.toggleGridButton:Update()
|
|
f.head.toggleGridButton:SetScript("OnMouseDown", f.head.toggleGridButton.UpdatePushed)
|
|
f.head.toggleGridButton:SetScript("OnMouseUp", f.head.toggleGridButton.Update)
|
|
f.head.toggleGridButton:SetScript("OnClick", function(self)
|
|
self.list:ToggleGridView()
|
|
self:Update()
|
|
S.Tooltip.CreateLocalized(self, "ANCHOR_LEFT", self.tooltipText)
|
|
end)
|
|
f.head.toggleGridButton:SetScript("OnEnter", function(self)
|
|
S.Tooltip.CreateLocalized(self, "ANCHOR_LEFT", self.tooltipText)
|
|
end)
|
|
f.head.toggleGridButton:SetScript("OnLeave", S.Tooltip.Cancel)
|
|
|
|
f.columnHeadings = {}
|
|
for k, v in pairs(tColumns) do
|
|
local b = CreateColumnButton(self, k)
|
|
|
|
-- Column dragging
|
|
b:SetScript("OnClick", ColumnOnClick)
|
|
b:SetScript("OnMouseDown", function(self)
|
|
self.list.dragging = self.key
|
|
self.list.movedColumn = false
|
|
end)
|
|
b:SetScript("OnMouseUp", function(self)
|
|
self.list.dragging = nil
|
|
end)
|
|
b:SetScript("OnEnter", function(self)
|
|
if self.list.dragging then
|
|
self.list.movedColumn = true
|
|
for i,v in ipairs(self.list:GetColumnOrder()) do
|
|
if v == self.key then
|
|
self.list:GetColumnOrder()[i] = self.list.dragging
|
|
elseif v == self.list.dragging then
|
|
self.list:GetColumnOrder()[i] = self.key
|
|
end
|
|
end
|
|
self.list:UpdateColumns()
|
|
end
|
|
end)
|
|
|
|
f.columnHeadings[k] = b
|
|
if k == "FAVORITES" then
|
|
b.favoriteIcon = b:CreateTexture(nil, "OVERLAY")
|
|
b.favoriteIcon:SetTexture("Interface\\Addons\\Sorted\\Textures\\Favorite-Icons")
|
|
b.favoriteIcon:SetPoint("CENTER")
|
|
b.favoriteIcon:SetSize(20, 20)
|
|
end
|
|
end
|
|
end
|
|
|
|
S.Utils.RunOnEvent(self, "SettingChanged-padding", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(true, false)
|
|
end
|
|
end)
|
|
S.Utils.RunOnEvent(self, "SettingChanged-iconSize", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(true, false)
|
|
self:UpdateColumns()
|
|
end
|
|
end)
|
|
S.Utils.RunOnEvent(self, "SettingChanged-iconBorderThickness", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(true, false)
|
|
self:UpdateColumns()
|
|
end
|
|
end)
|
|
S.Utils.RunOnEvent(self, "SettingChanged-paddingGrid", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(true, false)
|
|
end
|
|
end)
|
|
S.Utils.RunOnEvent(self, "SettingChanged-iconSizeGrid", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(true, false)
|
|
self:UpdateColumns()
|
|
end
|
|
end)
|
|
S.Utils.RunOnEvent(self, "SettingChanged-iconBorderThicknessGrid", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(true, false)
|
|
self:UpdateColumns()
|
|
end
|
|
end)
|
|
S.Utils.RunOnEvent(self, "SettingChanged-iconBorders", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(false, false)
|
|
end
|
|
end)
|
|
S.Utils.RunOnEvent(self, "SettingChanged-iconBordersGrid", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(false, false)
|
|
end
|
|
end)
|
|
S.Utils.RunOnEvent(self, "SettingChanged-combineStacks", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(true, true)
|
|
end
|
|
end)
|
|
S.Utils.RunOnEvent(self, "SettingChanged-newOnTop", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(false, true)
|
|
end
|
|
end)
|
|
|
|
S.Utils.RunOnEvent(self, "ColumnsChanged", function(self)
|
|
if self:IsShown() then
|
|
self:UpdateColumns()
|
|
end
|
|
end)
|
|
|
|
S.Utils.RunOnEvent(self, "GroupingChanged", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(false, true)
|
|
end
|
|
end)
|
|
|
|
S.Utils.RunOnEvent(self, "FavoriteChanged", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(false, true)
|
|
end
|
|
end)
|
|
|
|
S.Utils.RunOnEvent(self, "SortingChanged", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(false, true)
|
|
--self.scrollBar:SetValue(0)
|
|
end
|
|
end)
|
|
|
|
S.Utils.RunOnEvent(self, "Resized", function(self)
|
|
if self:IsShown() then
|
|
self:ScheduleUpdate(true, false)
|
|
end
|
|
end)
|
|
|
|
S.Utils.RunOnEvent(self, "EnteredWorld", function(self)
|
|
self:ScheduleUpdate(true, true)
|
|
end)
|
|
|
|
-- Update everything on show, since updates are disabled when the frame is hidden for performance
|
|
self.OnShow = function(self)
|
|
self:ScheduleUpdate(true, true)
|
|
self:ScrollToTop()
|
|
end
|
|
self:SetScript("OnShow", self.OnShow)
|
|
|
|
return self
|
|
end
|