ee0b350aba
- Dungeon followers now correctly show into the damage done section. - Fixed an error while statusbar plugin options. - Framework update. - Mythic Dungeon Plus code has been separated into six files (was just 2), this will help with the organization and maintenance of the code.
773 lines
24 KiB
Lua
773 lines
24 KiB
Lua
|
|
---@type detailsframework
|
|
local detailsFramework = _G["DetailsFramework"]
|
|
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
|
return
|
|
end
|
|
|
|
local CreateFrame = CreateFrame
|
|
local GetSpellInfo = GetSpellInfo
|
|
local GameTooltip = GameTooltip
|
|
local unpack = unpack
|
|
|
|
---mixin to use with DetailsFramework:Mixin(table, detailsFramework.SortFunctions)
|
|
---add methods to be used on scrollframes
|
|
---@class df_scrollboxmixin
|
|
detailsFramework.ScrollBoxFunctions = {
|
|
--set a function to run right before the refresh function (scroll:Refresh())
|
|
--this function receives the same parameters as the refresh function
|
|
SetPreRefreshFunction = function(self, func)
|
|
self.pre_refresh_func = func
|
|
end,
|
|
|
|
---refresh the scrollbox by resetting all lines created with :CreateLine(), then calling the refresh_func which was set at :CreateScrollBox()
|
|
---@param self table
|
|
---@return table
|
|
Refresh = function(self)
|
|
--hide all frames and tag as not in use
|
|
self._LinesInUse = 0
|
|
--self.Frames has a list of frames used by the scrollbox
|
|
for index, frame in ipairs(self.Frames) do
|
|
if (not self.DontHideChildrenOnPreRefresh) then
|
|
frame:Hide()
|
|
end
|
|
--set the frame as not in use
|
|
frame._InUse = nil
|
|
end
|
|
|
|
local offset = 0
|
|
if (self.IsFauxScroll) then
|
|
self:UpdateFaux(#self.data, self.LineAmount, self.LineHeight)
|
|
offset = self:GetOffsetFaux()
|
|
end
|
|
|
|
--before starting the refresh, check if there's a pre refresh function and call it
|
|
if (self.pre_refresh_func) then
|
|
detailsFramework:Dispatch(self.pre_refresh_func, self, self.data, offset, self.LineAmount)
|
|
end
|
|
|
|
--call the refresh function
|
|
detailsFramework:Dispatch(self.refresh_func, self, self.data, offset, self.LineAmount)
|
|
|
|
--hide all frames that are not in use
|
|
for index, frame in ipairs(self.Frames) do
|
|
--the member _InUse is true when the line is used by the refresh function
|
|
--this member is set to true when the code calls scrollBox:GetLine(index)
|
|
if (not frame._InUse) then
|
|
frame:Hide()
|
|
else
|
|
frame:Show()
|
|
end
|
|
end
|
|
|
|
self:Show()
|
|
|
|
local frameName = self:GetName()
|
|
if (frameName) then
|
|
if (self.HideScrollBar) then
|
|
local scrollBar = _G[frameName .. "ScrollBar"]
|
|
if (scrollBar) then
|
|
scrollBar:Hide()
|
|
end
|
|
else
|
|
--[=[ --maybe in the future I visit this again
|
|
local scrollBar = _G[frameName .. "ScrollBar"]
|
|
local height = self:GetHeight()
|
|
local totalLinesRequired = #self.data
|
|
local linesShown = self._LinesInUse
|
|
|
|
local percent = linesShown / totalLinesRequired
|
|
local thumbHeight = height * percent
|
|
scrollBar.ThumbTexture:SetSize(12, thumbHeight)
|
|
print("thumbHeight:", thumbHeight)
|
|
--]=]
|
|
end
|
|
end
|
|
return self.Frames
|
|
end,
|
|
|
|
OnVerticalScroll = function(self, offset)
|
|
self:OnVerticalScrollFaux(offset, self.LineHeight, self.Refresh)
|
|
return true
|
|
end,
|
|
|
|
---create a line within the scrollbox
|
|
---@param self table is the scrollbox
|
|
---@param func function|nil function to create the line object, this function will receive the line index as argument and return a table with the line object
|
|
---@return table line object (table)
|
|
CreateLine = function(self, func)
|
|
if (not func) then
|
|
func = self.CreateLineFunc
|
|
end
|
|
|
|
local okay, newLine = xpcall(func, geterrorhandler(), self, #self.Frames+1)
|
|
if (okay) then
|
|
if (not newLine) then
|
|
error("ScrollFrame:CreateLine() function did not returned a line, use: 'return line'")
|
|
end
|
|
table.insert(self.Frames, newLine)
|
|
newLine.Index = #self.Frames
|
|
return newLine
|
|
end
|
|
return newLine
|
|
end,
|
|
|
|
CreateLines = function(self, callback, lineAmount)
|
|
for i = 1, lineAmount do
|
|
self:CreateLine(callback)
|
|
end
|
|
end,
|
|
|
|
GetLine = function(self, lineIndex)
|
|
local line = self.Frames[lineIndex]
|
|
if (line) then
|
|
line._InUse = true
|
|
end
|
|
|
|
self._LinesInUse = self._LinesInUse + 1
|
|
return line
|
|
end,
|
|
|
|
SetData = function(self, data)
|
|
self.data = data
|
|
if (self.OnSetData) then
|
|
detailsFramework:CoreDispatch((self:GetName() or "ScrollBox") .. ":OnSetData()", self.OnSetData, self, self.data)
|
|
end
|
|
end,
|
|
|
|
GetData = function(self)
|
|
return self.data
|
|
end,
|
|
|
|
GetFrames = function(self)
|
|
return self.Frames
|
|
end,
|
|
|
|
GetLines = function(self) --alias of GetFrames
|
|
return self.Frames
|
|
end,
|
|
|
|
GetNumFramesCreated = function(self)
|
|
return #self.Frames
|
|
end,
|
|
|
|
GetNumFramesShown = function(self)
|
|
return self.LineAmount
|
|
end,
|
|
|
|
SetNumFramesShown = function(self, newAmount)
|
|
--hide frames which won't be used
|
|
if (newAmount < #self.Frames) then
|
|
for i = newAmount+1, #self.Frames do
|
|
self.Frames[i]:Hide()
|
|
end
|
|
end
|
|
--set the new amount
|
|
self.LineAmount = newAmount
|
|
end,
|
|
|
|
SetFramesHeight = function(self, height)
|
|
self.LineHeight = height
|
|
self:OnSizeChanged()
|
|
self:Refresh()
|
|
end,
|
|
|
|
OnSizeChanged = function(self)
|
|
if (self.ReajustNumFrames) then
|
|
--how many lines the scroll can show
|
|
local amountOfFramesToShow = math.floor(self:GetHeight() / self.LineHeight)
|
|
|
|
--how many lines the scroll already have
|
|
local totalFramesCreated = self:GetNumFramesCreated()
|
|
|
|
--how many lines are current shown
|
|
local totalFramesShown = self:GetNumFramesShown()
|
|
|
|
--the amount of frames increased
|
|
if (amountOfFramesToShow > totalFramesShown) then
|
|
for i = totalFramesShown+1, amountOfFramesToShow do
|
|
--check if need to create a new line
|
|
if (i > totalFramesCreated) then
|
|
self:CreateLine(self.CreateLineFunc)
|
|
end
|
|
end
|
|
|
|
--the amount of frames decreased
|
|
elseif (amountOfFramesToShow < totalFramesShown) then
|
|
--hide all frames above the new amount to show
|
|
for i = totalFramesCreated, amountOfFramesToShow, -1 do
|
|
if (self.Frames[i]) then
|
|
self.Frames[i]:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
--set the new amount of frames
|
|
self:SetNumFramesShown(amountOfFramesToShow)
|
|
--refresh lines
|
|
self:Refresh()
|
|
end
|
|
end,
|
|
|
|
--moved functions from blizzard faux scroll that are called from insecure code environment
|
|
--this reduces the amount of taints while using the faux scroll frame
|
|
GetOffsetFaux = function(self)
|
|
return self.offset or 0
|
|
end,
|
|
|
|
OnVerticalScrollFaux = function(self, value, lineHeight, updateFunction)
|
|
local scrollbar = self:GetChildFramesFaux()
|
|
scrollbar:SetValue(value)
|
|
self.offset = math.floor((value / lineHeight) + 0.5)
|
|
|
|
if (updateFunction) then
|
|
updateFunction(self)
|
|
end
|
|
end,
|
|
|
|
GetChildFramesFaux = function(frame)
|
|
local frameName = frame:GetName();
|
|
if frameName then
|
|
return _G[ frameName.."ScrollBar" ], _G[ frameName.."ScrollChildFrame" ], _G[ frameName.."ScrollBarScrollUpButton" ], _G[ frameName.."ScrollBarScrollDownButton" ];
|
|
else
|
|
return frame.ScrollBar, frame.ScrollChildFrame, frame.ScrollBar.ScrollUpButton, frame.ScrollBar.ScrollDownButton;
|
|
end
|
|
end,
|
|
|
|
UpdateFaux = function(frame, numItems, numToDisplay, buttonHeight, button, smallWidth, bigWidth, highlightFrame, smallHighlightWidth, bigHighlightWidth, alwaysShowScrollBar)
|
|
local scrollBar, scrollChildFrame, scrollUpButton, scrollDownButton = frame:GetChildFramesFaux();
|
|
-- If more than one screen full of items then show the scrollbar
|
|
local showScrollBar;
|
|
if ( numItems > numToDisplay or alwaysShowScrollBar ) then
|
|
frame:Show();
|
|
showScrollBar = 1;
|
|
else
|
|
scrollBar:SetValue(0);
|
|
frame:Hide();
|
|
end
|
|
if ( frame:IsShown() ) then
|
|
local scrollFrameHeight = 0;
|
|
local scrollChildHeight = 0;
|
|
|
|
if ( numItems > 0 ) then
|
|
scrollFrameHeight = (numItems - numToDisplay) * buttonHeight;
|
|
scrollChildHeight = numItems * buttonHeight;
|
|
if ( scrollFrameHeight < 0 ) then
|
|
scrollFrameHeight = 0;
|
|
end
|
|
scrollChildFrame:Show();
|
|
else
|
|
scrollChildFrame:Hide();
|
|
end
|
|
local maxRange = (numItems - numToDisplay) * buttonHeight;
|
|
if (maxRange < 0) then
|
|
maxRange = 0;
|
|
end
|
|
scrollBar:SetMinMaxValues(0, maxRange);
|
|
scrollBar:SetValueStep(buttonHeight);
|
|
scrollBar:SetStepsPerPage(numToDisplay-1);
|
|
scrollChildFrame:SetHeight(scrollChildHeight);
|
|
|
|
-- Arrow button handling
|
|
if ( scrollBar:GetValue() == 0 ) then
|
|
scrollUpButton:Disable();
|
|
else
|
|
scrollUpButton:Enable();
|
|
end
|
|
if ((scrollBar:GetValue() - scrollFrameHeight) == 0) then
|
|
scrollDownButton:Disable();
|
|
else
|
|
scrollDownButton:Enable();
|
|
end
|
|
|
|
-- Shrink because scrollbar is shown
|
|
if ( highlightFrame ) then
|
|
highlightFrame:SetWidth(smallHighlightWidth);
|
|
end
|
|
if ( button ) then
|
|
for i=1, numToDisplay do
|
|
_G[button..i]:SetWidth(smallWidth);
|
|
end
|
|
end
|
|
else
|
|
-- Widen because scrollbar is hidden
|
|
if ( highlightFrame ) then
|
|
highlightFrame:SetWidth(bigHighlightWidth);
|
|
end
|
|
if ( button ) then
|
|
for i=1, numToDisplay do
|
|
_G[button..i]:SetWidth(bigWidth);
|
|
end
|
|
end
|
|
end
|
|
|
|
return showScrollBar;
|
|
end,
|
|
}
|
|
|
|
|
|
---@class df_gridscrollbox_options : table
|
|
---@field width number?
|
|
---@field height number?
|
|
---@field line_amount number?
|
|
---@field line_height number?
|
|
---@field columns_per_line number?
|
|
---@field auto_amount boolean?
|
|
---@field no_scroll boolean?
|
|
---@field vertical_padding number?
|
|
---@field no_backdrop boolean?
|
|
|
|
---@type df_gridscrollbox_options
|
|
local grid_scrollbox_options = {
|
|
width = 600,
|
|
height = 400,
|
|
line_amount = 10,
|
|
line_height = 30,
|
|
columns_per_line = 4,
|
|
no_scroll = false,
|
|
vertical_padding = 1,
|
|
no_backdrop = false,
|
|
}
|
|
|
|
---@class df_gridscrollbox : df_scrollbox
|
|
|
|
---create a scrollbox with a grid layout
|
|
---@param parent frame
|
|
---@param name string
|
|
---@param refreshFunc function
|
|
---@param data table
|
|
---@param createColumnFrameFunc function
|
|
---@param options df_gridscrollbox_options?
|
|
---@return unknown
|
|
function detailsFramework:CreateGridScrollBox(parent, name, refreshFunc, data, createColumnFrameFunc, options)
|
|
options = options or {}
|
|
|
|
--check values passed, get defaults and cast values due to the scrollbox require some values to be numbers
|
|
local width = type(options.width) == "number" and options.width or grid_scrollbox_options.width
|
|
---@cast width number
|
|
|
|
local height = type(options.height) == "number" and options.height or grid_scrollbox_options.height
|
|
---@cast height number
|
|
|
|
local lineAmount = type(options.line_amount) == "number" and options.line_amount or grid_scrollbox_options.line_amount
|
|
---@cast lineAmount number
|
|
|
|
local lineHeight = type(options.line_height) == "number" and options.line_height or grid_scrollbox_options.line_height
|
|
---@cast lineHeight number
|
|
|
|
local columnsPerLine = options.columns_per_line or grid_scrollbox_options.columns_per_line
|
|
local autoAmount = options.auto_amount
|
|
local noScroll = options.no_scroll
|
|
local noBackdrop = options.no_backdrop
|
|
local verticalPadding = options.vertical_padding or grid_scrollbox_options.vertical_padding
|
|
|
|
local createLineFunc = function(scrollBox, lineIndex)
|
|
local line = CreateFrame("frame", "$parentLine" .. lineIndex, scrollBox)
|
|
line:SetSize(width, lineHeight)
|
|
line:SetPoint("top", scrollBox, "top", 0, -((lineIndex-1) * (lineHeight + verticalPadding)))
|
|
line.optionFrames = {}
|
|
|
|
for columnIndex = 1, columnsPerLine do
|
|
--dispatch payload: line, lineIndex, columnIndex
|
|
local optionFrame = createColumnFrameFunc(line, lineIndex, columnIndex)
|
|
line.optionFrames[columnIndex] = optionFrame
|
|
optionFrame:SetPoint("left", line, "left", (columnIndex-1) * (width/columnsPerLine), 0)
|
|
end
|
|
|
|
return line
|
|
end
|
|
|
|
local onSetData = function(self, data)
|
|
local newData = {}
|
|
|
|
for i = 1, #data, columnsPerLine do
|
|
local thisColumnData = {}
|
|
|
|
for o = 1, columnsPerLine do
|
|
local index = i + (o-1)
|
|
local thisData = data[index]
|
|
if (thisData) then
|
|
thisColumnData[#thisColumnData+1] = thisData
|
|
end
|
|
end
|
|
newData[#newData+1] = thisColumnData
|
|
end
|
|
|
|
self.data = newData
|
|
end
|
|
|
|
local refreshGrid = function(scrollBox, thisData, offset, totalLines)
|
|
for i = 1, totalLines do
|
|
local index = i + offset
|
|
local lineData = thisData[index]
|
|
|
|
if (lineData) then
|
|
local line = scrollBox:GetLine(i)
|
|
for o = 1, columnsPerLine do
|
|
local optionFrame = line.optionFrames[o]
|
|
local data = lineData[o]
|
|
if (data) then
|
|
detailsFramework:Dispatch(refreshFunc, optionFrame, data)
|
|
optionFrame:Show()
|
|
line:Show()
|
|
else
|
|
optionFrame:Hide()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if (not name) then
|
|
name = "DetailsFrameworkAuraScrollBox" .. math.random(1, 9999999)
|
|
end
|
|
|
|
local scrollBox = detailsFramework:CreateScrollBox(parent, name, refreshGrid, data, width, height, lineAmount, lineHeight, createLineFunc, autoAmount, noScroll, noBackdrop)
|
|
scrollBox:CreateLines(createLineFunc, lineAmount)
|
|
detailsFramework:ReskinSlider(scrollBox)
|
|
scrollBox.OnSetData = onSetData
|
|
onSetData(scrollBox, data)
|
|
|
|
return scrollBox
|
|
end
|
|
|
|
function detailsFramework.CreateRoundedOptionsScrollBox(parent, name, onRefreshButton, onSelectOption, tbdData, createSelectorButton, gridScrollBoxOptions)
|
|
---when the scroll is refreshing the line, the line will call this function for each selection button on it
|
|
---@param button df_button
|
|
---@param data table
|
|
local refreshAuraSelectorFrame = function(button, data)
|
|
button.data = data
|
|
|
|
if (data.tooltip) then
|
|
button.tooltip = data.tooltip
|
|
end
|
|
|
|
xpcall(onRefreshButton, geterrorhandler(), button, data)
|
|
|
|
--set what happen when the user clicks the button
|
|
button:SetClickFunction(onSelectOption, button, data)
|
|
end
|
|
end
|
|
|
|
--Need to test this and check the "same_name_spells_add(value)" on the OnEnter function
|
|
--also need to make sure this can work with any data (global, class, spec) and aura type (buff, debuff)
|
|
|
|
--aura scroll box
|
|
---@class df_aurascrollbox_options : table
|
|
---@field line_height number?
|
|
---@field line_amount number?
|
|
---@field width number?
|
|
---@field height number?
|
|
---@field vertical_padding number?
|
|
---@field show_spell_tooltip boolean
|
|
---@field remove_icon_border boolean
|
|
---@field no_scroll boolean
|
|
---@field no_backdrop boolean
|
|
---@field backdrop_onenter number[]?
|
|
---@field backdrop_onleave number[]?
|
|
---@field font_size number?
|
|
---@field title_text string?
|
|
|
|
local auraScrollDefaultSettings = {
|
|
line_height = 18,
|
|
line_amount = 18,
|
|
width = 300,
|
|
height = 500,
|
|
vertical_padding = 1,
|
|
show_spell_tooltip = false,
|
|
remove_icon_border = true,
|
|
no_scroll = false,
|
|
no_backdrop = false,
|
|
backdrop_onenter = {.8, .8, .8, 0.4},
|
|
backdrop_onleave = {.8, .8, .8, 0.2},
|
|
font_size = 12,
|
|
title_text = "",
|
|
}
|
|
|
|
---@param parent frame
|
|
---@param name string?
|
|
---@param data table? --can be set later with :SetData()
|
|
---@param onAuraRemoveCallback function?
|
|
---@param options df_aurascrollbox_options?
|
|
function detailsFramework:CreateAuraScrollBox(parent, name, data, onAuraRemoveCallback, options)
|
|
--hack the construction of the options table here, as the scrollbox is created much later
|
|
options = options or {}
|
|
local scrollOptions = {}
|
|
detailsFramework.OptionsFunctions.BuildOptionsTable(scrollOptions, auraScrollDefaultSettings, options)
|
|
options = scrollOptions.options
|
|
|
|
local refreshAuraLines = function(self, data, offset, totalLines)
|
|
for i = 1, totalLines do
|
|
local index = i + offset
|
|
local auraTable = data[index]
|
|
if (auraTable) then
|
|
local line = self:GetLine(i)
|
|
local spellId, spellName, spellIcon, lowerSpellName, bAddedBySpellName = unpack(auraTable)
|
|
|
|
line.SpellID = spellId
|
|
line.SpellName = spellName
|
|
line.SpellNameLower = lowerSpellName
|
|
line.SpellIcon = spellIcon
|
|
line.Flag = bAddedBySpellName
|
|
|
|
if (bAddedBySpellName) then
|
|
line.name:SetText(spellName)
|
|
else
|
|
line.name:SetText(spellName .. " (" .. spellId .. ")")
|
|
end
|
|
|
|
line.icon:SetTexture(spellIcon)
|
|
if (options.remove_icon_border) then
|
|
line.icon:SetTexCoord(.1, .9, .1, .9)
|
|
else
|
|
line.icon:SetTexCoord(0, 1, 0, 1)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local onLeaveAuraLine = function(self)
|
|
self:SetBackdropColor(unpack(options.backdrop_onleave))
|
|
GameTooltip:Hide()
|
|
GameCooltip:Hide()
|
|
end
|
|
|
|
local onEnterAuraLine = function(line)
|
|
if (options.show_spell_tooltip and line.SpellID and GetSpellInfo(line.SpellID)) then
|
|
GameTooltip:SetOwner(line, "ANCHOR_CURSOR")
|
|
GameTooltip:SetSpellByID(line.SpellID)
|
|
GameTooltip:AddLine(" ")
|
|
GameTooltip:Show()
|
|
end
|
|
line:SetBackdropColor(unpack(options.backdrop_onenter))
|
|
|
|
local bTrackByName = line.Flag --the user entered the spell name to track the spell (and not a spellId)
|
|
local spellId = line.SpellID
|
|
|
|
if (bTrackByName) then --the user entered the spell name to track the spell
|
|
local spellsHashMap, spellsIndexTable, spellsWithSameName = detailsFramework:GetSpellCaches()
|
|
if (spellsWithSameName) then
|
|
local spellName, _, spellIcon = GetSpellInfo(spellId)
|
|
if (spellName) then
|
|
local spellNameLower = spellName:lower()
|
|
local sameNameSpells = spellsWithSameName[spellNameLower]
|
|
|
|
if (sameNameSpells) then
|
|
GameCooltip:Preset(2)
|
|
GameCooltip:SetOwner(line, "left", "right", 2, 0)
|
|
GameCooltip:SetOption("TextSize", 10)
|
|
|
|
for i, thisSpellId in ipairs(sameNameSpells) do
|
|
GameCooltip:AddLine(spellName .. " (" .. thisSpellId .. ")")
|
|
GameCooltip:AddIcon(spellIcon, 1, 1, 14, 14, .1, .9, .1, .9)
|
|
end
|
|
|
|
GameCooltip:Show()
|
|
end
|
|
end
|
|
end
|
|
|
|
else --the user entered the spellId to track the spell
|
|
GameCooltip:Preset(2)
|
|
GameCooltip:SetOwner(line, "left", "right", 2, 0)
|
|
GameCooltip:SetOption("TextSize", 10)
|
|
|
|
local spellName, _, spellIcon = GetSpellInfo(spellId)
|
|
if (spellName) then
|
|
GameCooltip:AddLine(spellName .. " (" .. spellId .. ")")
|
|
GameCooltip:AddIcon(spellIcon, 1, 1, 14, 14, .1, .9, .1, .9)
|
|
end
|
|
GameCooltip:Show()
|
|
end
|
|
end
|
|
|
|
local onClickAuraRemoveButton = function(self)
|
|
local spellId = tonumber(self:GetParent().SpellID)
|
|
if (spellId and type(spellId) == "number") then
|
|
--button > line > scrollbox
|
|
local scrollBox = self:GetParent():GetParent()
|
|
scrollBox.data_original[spellId] = nil
|
|
scrollBox.data_original["" .. (spellId or "")] = nil -- cleanup...
|
|
|
|
scrollBox:TransformAuraData()
|
|
scrollBox:Refresh()
|
|
|
|
if (onAuraRemoveCallback) then --upvalue
|
|
detailsFramework:QuickDispatch(onAuraRemoveCallback, spellId)
|
|
end
|
|
end
|
|
end
|
|
|
|
local createLineFunc = function(self, index)
|
|
local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate")
|
|
local scrollBoxWidth = options.width
|
|
local lineHeight = options.line_height
|
|
local verticalPadding = options.vertical_padding
|
|
|
|
line:SetPoint("topleft", self, "topleft", 1, -((index-1) * (lineHeight + verticalPadding)) - 1)
|
|
line:SetSize(scrollBoxWidth - 2, lineHeight)
|
|
line:SetScript("OnEnter", onEnterAuraLine)
|
|
line:SetScript("OnLeave", onLeaveAuraLine)
|
|
|
|
line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
|
line:SetBackdropColor(unpack(options.backdrop_onleave))
|
|
|
|
local iconTexture = line:CreateTexture("$parentIcon", "overlay")
|
|
iconTexture:SetSize(lineHeight - 2, lineHeight - 2)
|
|
|
|
local spellNameFontString = line:CreateFontString("$parentName", "overlay", "GameFontNormal")
|
|
detailsFramework:SetFontSize(spellNameFontString, options.font_size)
|
|
|
|
local removeButton = CreateFrame("button", "$parentRemoveButton", line, "UIPanelCloseButton")
|
|
removeButton:SetSize(16, 16)
|
|
removeButton:SetScript("OnClick", onClickAuraRemoveButton)
|
|
removeButton:SetPoint("topright", line, "topright", 0, 0)
|
|
removeButton:GetNormalTexture():SetDesaturated(true)
|
|
|
|
iconTexture:SetPoint("left", line, "left", 2, 0)
|
|
spellNameFontString:SetPoint("left", iconTexture, "right", 3, 0)
|
|
|
|
line.icon = iconTexture
|
|
line.name = spellNameFontString
|
|
line.removebutton = removeButton
|
|
|
|
return line
|
|
end
|
|
|
|
---@class df_aurascrollbox : df_scrollbox
|
|
---@field data_original table
|
|
---@field refresh_original function
|
|
---@field TitleLabel fontstring
|
|
---@field TransformAuraData fun(self:df_aurascrollbox)
|
|
---@field GetTitleFontString fun(self:df_aurascrollbox): fontstring
|
|
|
|
data = data or {}
|
|
|
|
if (not name) then
|
|
name = "DetailsFrameworkAuraScrollBox" .. math.random(1, 9999999)
|
|
end
|
|
|
|
local auraScrollBox = detailsFramework:CreateScrollBox(parent, name, refreshAuraLines, data, options.width, options.height, options.line_amount, options.line_height)
|
|
detailsFramework:ReskinSlider(auraScrollBox)
|
|
---@cast auraScrollBox df_aurascrollbox
|
|
auraScrollBox.data_original = data
|
|
|
|
local titleLabel = auraScrollBox:CreateFontString("$parentTitleLabel", "overlay", "GameFontNormal")
|
|
titleLabel:SetPoint("bottomleft", auraScrollBox, "topleft", 0, 2)
|
|
detailsFramework:SetFontColor(titleLabel, "silver")
|
|
detailsFramework:SetFontSize(titleLabel, 10)
|
|
auraScrollBox.TitleLabel = titleLabel
|
|
|
|
function auraScrollBox:GetTitleFontString()
|
|
return self.TitleLabel
|
|
end
|
|
|
|
for i = 1, options.line_amount do
|
|
auraScrollBox:CreateLine(createLineFunc)
|
|
end
|
|
|
|
function auraScrollBox:TransformAuraData()
|
|
local newData = {}
|
|
local added = {}
|
|
|
|
for spellId, bAddedBySpellName in pairs(self.data_original) do
|
|
local spellName, _, spellIcon = GetSpellInfo(spellId)
|
|
if (spellName and not added[tonumber(spellId) or 0]) then
|
|
local lowerSpellName = spellName:lower()
|
|
table.insert(newData, {spellId, spellName, spellIcon, lowerSpellName, bAddedBySpellName})
|
|
added[tonumber(spellId) or 0] = true
|
|
end
|
|
end
|
|
|
|
table.sort(newData, function(t1, t2) return t1[4] < t2[4] end)
|
|
self.data = newData
|
|
end
|
|
|
|
auraScrollBox.SetData = function(self, data)
|
|
self.data_original = data
|
|
self.data = data
|
|
auraScrollBox:TransformAuraData()
|
|
end
|
|
|
|
auraScrollBox.GetData = function(self)
|
|
return self.data_original
|
|
end
|
|
|
|
auraScrollBox.refresh_original = auraScrollBox.Refresh
|
|
|
|
auraScrollBox.Refresh = function()
|
|
auraScrollBox:TransformAuraData()
|
|
auraScrollBox:refresh_original()
|
|
end
|
|
|
|
auraScrollBox:SetData(data)
|
|
|
|
return auraScrollBox
|
|
end
|
|
|
|
|
|
detailsFramework.CanvasScrollBoxMixin = {
|
|
SetScrollSpeed = function(self, speed)
|
|
assert(type(speed) == "number", "CanvasScrollBox:SetScrollSpeed(speed): speed must be a number.")
|
|
self.scrollStep = speed
|
|
end,
|
|
|
|
GetScrollSpeed = function(self)
|
|
return self.scrollStep
|
|
end,
|
|
|
|
OnVerticalScroll = function(self, delta)
|
|
local scrollStep = self:GetScrollSpeed()
|
|
if (delta > 0) then
|
|
self:SetVerticalScroll(math.max(self:GetVerticalScroll() - scrollStep, 0))
|
|
else
|
|
self:SetVerticalScroll(math.min(self:GetVerticalScroll() + scrollStep, self:GetVerticalScrollRange()))
|
|
end
|
|
end,
|
|
}
|
|
|
|
local canvasScrollBoxDefaultOptions = {
|
|
width = 600,
|
|
height = 400,
|
|
reskin_slider = true,
|
|
}
|
|
|
|
---@class df_canvasscrollbox : scrollframe, df_optionsmixin
|
|
---@field child frame
|
|
|
|
---@param parent frame
|
|
---@param child frame?
|
|
---@param name string?
|
|
---@param options table?
|
|
---@return df_canvasscrollbox
|
|
function detailsFramework:CreateCanvasScrollBox(parent, child, name, options)
|
|
---@type df_canvasscrollbox
|
|
local canvasScrollBox = CreateFrame("scrollframe", name or ("DetailsFrameworkCanvasScroll" .. math.random(50000, 10000000)), parent, "BackdropTemplate, UIPanelScrollFrameTemplate")
|
|
canvasScrollBox.scrollStep = 20
|
|
canvasScrollBox.minValue = 0
|
|
|
|
canvasScrollBox:SetScript("OnMouseWheel", detailsFramework.CanvasScrollBoxMixin.OnVerticalScroll)
|
|
|
|
detailsFramework:Mixin(canvasScrollBox, detailsFramework.CanvasScrollBoxMixin)
|
|
detailsFramework:Mixin(canvasScrollBox, detailsFramework.OptionsFunctions)
|
|
|
|
options = options or {}
|
|
canvasScrollBox:BuildOptionsTable(canvasScrollBoxDefaultOptions, options)
|
|
|
|
canvasScrollBox:SetSize(canvasScrollBox.options.width, canvasScrollBox.options.height)
|
|
|
|
if (not child) then
|
|
child = CreateFrame("frame", "$parentChild", canvasScrollBox)
|
|
end
|
|
|
|
canvasScrollBox:SetScrollChild(child)
|
|
canvasScrollBox:EnableMouseWheel(true)
|
|
|
|
canvasScrollBox.child = child
|
|
|
|
if (canvasScrollBox.options.reskin_slider) then
|
|
detailsFramework:ReskinSlider(canvasScrollBox)
|
|
end
|
|
|
|
return canvasScrollBox
|
|
end |