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.
5710 lines
188 KiB
5710 lines
188 KiB
|
|
local detailsFramework = _G ["DetailsFramework"]
|
|
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
|
return
|
|
end
|
|
|
|
local _
|
|
--lua locals
|
|
local rawset = rawset --lua local
|
|
local rawget = rawget --lua local
|
|
local setmetatable = setmetatable --lua local
|
|
local unpack = table.unpack or unpack --lua local
|
|
local type = type --lua local
|
|
local floor = math.floor --lua local
|
|
local loadstring = loadstring --lua local
|
|
local CreateFrame = CreateFrame
|
|
|
|
local IS_WOW_PROJECT_MAINLINE = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE
|
|
local IS_WOW_PROJECT_NOT_MAINLINE = WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE
|
|
local IS_WOW_PROJECT_CLASSIC_ERA = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC
|
|
|
|
local CastInfo = detailsFramework.CastInfo
|
|
|
|
local PixelUtil = PixelUtil or DFPixelUtil
|
|
|
|
local UnitGroupRolesAssigned = detailsFramework.UnitGroupRolesAssigned
|
|
|
|
local cleanfunction = function() end
|
|
local APIFrameFunctions
|
|
|
|
do
|
|
local metaPrototype = {
|
|
WidgetType = "panel",
|
|
dversion = detailsFramework.dversion,
|
|
}
|
|
|
|
--check if there's a metaPrototype already existing
|
|
if (_G[detailsFramework.GlobalWidgetControlNames["panel"]]) then
|
|
--get the already existing metaPrototype
|
|
local oldMetaPrototype = _G[detailsFramework.GlobalWidgetControlNames ["panel"]]
|
|
--check if is older
|
|
if ( (not oldMetaPrototype.dversion) or (oldMetaPrototype.dversion < detailsFramework.dversion) ) then
|
|
--the version is older them the currently loading one
|
|
--copy the new values into the old metatable
|
|
for funcName, _ in pairs(metaPrototype) do
|
|
oldMetaPrototype[funcName] = metaPrototype[funcName]
|
|
end
|
|
end
|
|
else
|
|
--first time loading the framework
|
|
_G[detailsFramework.GlobalWidgetControlNames["panel"]] = metaPrototype
|
|
end
|
|
end
|
|
|
|
local PanelMetaFunctions = _G[detailsFramework.GlobalWidgetControlNames["panel"]]
|
|
detailsFramework:Mixin(PanelMetaFunctions, detailsFramework.ScriptHookMixin)
|
|
|
|
--default options for the frame layout
|
|
---@class df_framelayout_options : table
|
|
---@field amount_per_line number? 4
|
|
---@field start_x number? 2
|
|
---@field start_y number? -2
|
|
---@field is_vertical boolean? true if vertical, false if horizontal
|
|
---@field grow_right boolean? true to grow right, false to grow left
|
|
---@field grow_down boolean? true to grow down, false to grow up
|
|
---@field anchor_to_child boolean? true to anchor to the previous frame instead of coordinate
|
|
---@field anchor_point df_framelayout_point? "topleft"
|
|
---@field anchor_relative df_framelayout_point? "topleft"
|
|
---@field offset_x number? 100
|
|
---@field offset_y number? 20
|
|
---@field width number? 0
|
|
---@field min_width number? 0
|
|
---@field height number? 0
|
|
---@field break_if_hidden boolean? true to stop if encounters a hidden frame
|
|
---@field use__width boolean? if true it'll use the __width from the widget as the offset_x
|
|
|
|
local default_framelayout_options = {
|
|
amount_per_line = 4,
|
|
start_x = 2,
|
|
start_y = -2,
|
|
is_vertical = false,
|
|
grow_right = true, --on vertical (if not grow next line left)
|
|
grow_down = true, --on horizontal (if not grow next line up)
|
|
anchor_to_child = false, --if true set the point to the previous frame instead of coordinate
|
|
anchor_point = "topleft",
|
|
anchor_relative = "topleft",
|
|
offset_x = 100,
|
|
use__width = false, --__width from the widget
|
|
offset_y = 20,
|
|
width = 0, --if bigger than 0, it will set the value
|
|
min_width = 0,
|
|
height = 0,
|
|
break_if_hidden = true, --stop if encounters a hidden frame
|
|
}
|
|
|
|
---@alias df_framelayout_point
|
|
---| "top"
|
|
---| "bottom"
|
|
---| "left"
|
|
---| "right"
|
|
|
|
---@class df_framelayout : table
|
|
---@field AnchorTo fun(self:uiobject, anchor:uiobject, point:df_framelayout_point, x:number?, y:number?)
|
|
---@field ArrangeFrames fun(self:uiobject, frameList:table<uiobject>[], options:df_framelayout_options?)
|
|
|
|
|
|
--mixin for frame layout
|
|
detailsFramework.LayoutFrame = {
|
|
AnchorTo = function(self, anchor, point, x, y)
|
|
if (point == "top") then
|
|
self:ClearAllPoints()
|
|
self:SetPoint("bottom", anchor, "top", x or 0, y or 0)
|
|
|
|
elseif (point == "bottom") then
|
|
self:ClearAllPoints()
|
|
self:SetPoint("top", anchor, "bottom", x or 0, y or 0)
|
|
|
|
elseif (point == "left") then
|
|
self:ClearAllPoints()
|
|
self:SetPoint("right", anchor, "left", x or 0, y or 0)
|
|
|
|
elseif (point == "right") then
|
|
self:ClearAllPoints()
|
|
self:SetPoint("left", anchor, "right", x or 0, y or 0)
|
|
end
|
|
end,
|
|
|
|
ArrangeFrames = function(self, frameList, options)
|
|
if (not frameList) then
|
|
frameList = {self:GetChildren()}
|
|
end
|
|
|
|
options = options or {}
|
|
detailsFramework.table.deploy(options, default_framelayout_options)
|
|
|
|
local breakLine = options.amount_per_line + 1
|
|
local currentX, currentY = options.start_x, options.start_y
|
|
local offsetX, offsetY = options.offset_x, options.offset_y
|
|
local anchorPoint = options.anchor_point
|
|
local anchorAt = options.anchor_relative
|
|
local latestFrame = self
|
|
local firstRowFrame = frameList[1]
|
|
|
|
if (options.is_vertical) then
|
|
for i = 1, #frameList do
|
|
local thisFrame = frameList[i]
|
|
if (options.break_if_hidden and not thisFrame:IsShown()) then
|
|
break
|
|
end
|
|
thisFrame:ClearAllPoints()
|
|
|
|
if (options.anchor_to_child) then
|
|
if (i == breakLine) then
|
|
if (options.grow_right) then
|
|
thisFrame:SetPoint("topleft", firstRowFrame, "topright", offsetX, 0)
|
|
else
|
|
thisFrame:SetPoint("topright", firstRowFrame, "topleft", -offsetX, 0)
|
|
end
|
|
firstRowFrame = thisFrame
|
|
latestFrame = thisFrame
|
|
breakLine = breakLine + options.amount_per_line
|
|
else
|
|
thisFrame:SetPoint(anchorPoint, latestFrame, i == 1 and "topleft" or anchorAt, offsetX, i == 1 and 0 or offsetY)
|
|
latestFrame = thisFrame
|
|
end
|
|
else
|
|
if (i == breakLine) then
|
|
if (options.grow_right) then
|
|
currentX = currentX + offsetX
|
|
else
|
|
currentX = currentX - offsetX
|
|
end
|
|
currentY = options.start_y
|
|
|
|
firstRowFrame = thisFrame
|
|
breakLine = breakLine + options.amount_per_line
|
|
end
|
|
|
|
thisFrame:SetPoint(anchorPoint, self, anchorAt, currentX, currentY)
|
|
|
|
if (options.use__height) then --use the childframe.__width
|
|
currentY = currentY - thisFrame.__height
|
|
|
|
elseif (options.min_height) then
|
|
currentY = currentY - math.max(options.min_height, offsetY)
|
|
else
|
|
currentY = currentY - offsetY
|
|
end
|
|
end
|
|
end
|
|
|
|
else
|
|
for i = 1, #frameList do
|
|
local thisFrame = frameList[i]
|
|
if (options.break_if_hidden and not thisFrame:IsShown()) then
|
|
break
|
|
end
|
|
|
|
thisFrame:ClearAllPoints()
|
|
|
|
if (options.anchor_to_child) then
|
|
if (i == breakLine) then
|
|
if (options.grow_down) then
|
|
thisFrame:SetPoint("topleft", firstRowFrame, "bottomleft", 0, -offsetY)
|
|
else
|
|
thisFrame:SetPoint("bottomleft", firstRowFrame, "topleft", 0, offsetY)
|
|
end
|
|
firstRowFrame = thisFrame
|
|
latestFrame = thisFrame
|
|
breakLine = breakLine + options.amount_per_line
|
|
else
|
|
thisFrame:SetPoint(anchorPoint, latestFrame, i == 1 and "topleft" or anchorAt, i == 1 and 0 or offsetX, offsetY)
|
|
latestFrame = thisFrame
|
|
end
|
|
else
|
|
if (i == breakLine) then
|
|
if (options.grow_down) then
|
|
currentY = currentY - offsetY
|
|
else
|
|
currentY = currentY + offsetY
|
|
end
|
|
currentX = options.start_x
|
|
|
|
firstRowFrame = thisFrame
|
|
breakLine = breakLine + options.amount_per_line
|
|
end
|
|
|
|
thisFrame:SetPoint(anchorPoint, self, anchorAt, currentX, currentY)
|
|
|
|
if (options.use__width) then --use the childframe.__width
|
|
currentX = currentX + thisFrame.__width
|
|
|
|
elseif (options.min_width) then
|
|
currentX = currentX + math.max(options.min_width, offsetX)
|
|
else
|
|
currentX = currentX + offsetX
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
}
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
--metatables
|
|
PanelMetaFunctions.__call = function(_table, value)
|
|
--nothing to do
|
|
return true
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
--members
|
|
--tooltip
|
|
local gmember_tooltip = function(_object)
|
|
return _object:GetTooltip()
|
|
end
|
|
--shown
|
|
local gmember_shown = function(_object)
|
|
return _object:IsShown()
|
|
end
|
|
--backdrop color
|
|
local gmember_color = function(_object)
|
|
return _object.frame:GetBackdropColor()
|
|
end
|
|
--backdrop table
|
|
local gmember_backdrop = function(_object)
|
|
return _object.frame:GetBackdrop()
|
|
end
|
|
--frame width
|
|
local gmember_width = function(_object)
|
|
return _object.frame:GetWidth()
|
|
end
|
|
--frame height
|
|
local gmember_height = function(_object)
|
|
return _object.frame:GetHeight()
|
|
end
|
|
--locked
|
|
local gmember_locked = function(_object)
|
|
return rawget(_object, "is_locked")
|
|
end
|
|
|
|
PanelMetaFunctions.GetMembers = PanelMetaFunctions.GetMembers or {}
|
|
PanelMetaFunctions.GetMembers ["tooltip"] = gmember_tooltip
|
|
PanelMetaFunctions.GetMembers ["shown"] = gmember_shown
|
|
PanelMetaFunctions.GetMembers ["color"] = gmember_color
|
|
PanelMetaFunctions.GetMembers ["backdrop"] = gmember_backdrop
|
|
PanelMetaFunctions.GetMembers ["width"] = gmember_width
|
|
PanelMetaFunctions.GetMembers ["height"] = gmember_height
|
|
PanelMetaFunctions.GetMembers ["locked"] = gmember_locked
|
|
|
|
PanelMetaFunctions.__index = function(object, key)
|
|
local func = PanelMetaFunctions.GetMembers[key]
|
|
if (func) then
|
|
return func(object, key)
|
|
end
|
|
|
|
local fromMe = rawget(object, key)
|
|
if (fromMe) then
|
|
return fromMe
|
|
end
|
|
|
|
return PanelMetaFunctions[key]
|
|
end
|
|
|
|
--tooltip
|
|
local smember_tooltip = function(_object, _value)
|
|
return _object:SetTooltip (_value)
|
|
end
|
|
--show
|
|
local smember_show = function(_object, _value)
|
|
if (_value) then
|
|
return _object:Show()
|
|
else
|
|
return _object:Hide()
|
|
end
|
|
end
|
|
--hide
|
|
local smember_hide = function(_object, _value)
|
|
if (not _value) then
|
|
return _object:Show()
|
|
else
|
|
return _object:Hide()
|
|
end
|
|
end
|
|
--backdrop color
|
|
local smember_color = function(_object, _value)
|
|
local _value1, _value2, _value3, _value4 = detailsFramework:ParseColors(_value)
|
|
return _object:SetBackdropColor(_value1, _value2, _value3, _value4)
|
|
end
|
|
--frame width
|
|
local smember_width = function(_object, _value)
|
|
return _object.frame:SetWidth(_value)
|
|
end
|
|
--frame height
|
|
local smember_height = function(_object, _value)
|
|
return _object.frame:SetHeight(_value)
|
|
end
|
|
|
|
--locked
|
|
local smember_locked = function(_object, _value)
|
|
if (_value) then
|
|
_object.frame:SetMovable(false)
|
|
return rawset(_object, "is_locked", true)
|
|
else
|
|
_object.frame:SetMovable(true)
|
|
rawset(_object, "is_locked", false)
|
|
return
|
|
end
|
|
end
|
|
|
|
--backdrop
|
|
local smember_backdrop = function(_object, _value)
|
|
return _object.frame:SetBackdrop(_value)
|
|
end
|
|
|
|
--close with right button
|
|
local smember_right_close = function(_object, _value)
|
|
return rawset(_object, "rightButtonClose", _value)
|
|
end
|
|
|
|
PanelMetaFunctions.SetMembers = PanelMetaFunctions.SetMembers or {}
|
|
PanelMetaFunctions.SetMembers["tooltip"] = smember_tooltip
|
|
PanelMetaFunctions.SetMembers["show"] = smember_show
|
|
PanelMetaFunctions.SetMembers["hide"] = smember_hide
|
|
PanelMetaFunctions.SetMembers["color"] = smember_color
|
|
PanelMetaFunctions.SetMembers["backdrop"] = smember_backdrop
|
|
PanelMetaFunctions.SetMembers["width"] = smember_width
|
|
PanelMetaFunctions.SetMembers["height"] = smember_height
|
|
PanelMetaFunctions.SetMembers["locked"] = smember_locked
|
|
PanelMetaFunctions.SetMembers["close_with_right"] = smember_right_close
|
|
|
|
PanelMetaFunctions.__newindex = function(_table, _key, _value)
|
|
local func = PanelMetaFunctions.SetMembers [_key]
|
|
if (func) then
|
|
return func (_table, _value)
|
|
else
|
|
return rawset(_table, _key, _value)
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
--methods
|
|
|
|
--right click to close
|
|
function PanelMetaFunctions:CreateRightClickLabel(textType, width, height, showCloseText)
|
|
local text
|
|
width = width or 20
|
|
height = height or 20
|
|
|
|
if (showCloseText) then
|
|
text = showCloseText
|
|
else
|
|
if (textType) then
|
|
textType = string.lower(textType)
|
|
if (textType == "short") then
|
|
text = "close window"
|
|
|
|
elseif (textType == "medium") then
|
|
text = "close window"
|
|
|
|
elseif (textType == "large") then
|
|
text = "close window"
|
|
end
|
|
else
|
|
text = "close window"
|
|
end
|
|
end
|
|
|
|
return detailsFramework:NewLabel(self, _, "$parentRightMouseToClose", nil, "|TInterface\\TUTORIALFRAME\\UI-TUTORIAL-FRAME:" .. width .. ":" .. height .. ":0:1:512:512:8:70:328:409|t " .. text)
|
|
end
|
|
|
|
--show & hide
|
|
function PanelMetaFunctions:Show()
|
|
self.frame:Show()
|
|
end
|
|
|
|
function PanelMetaFunctions:Hide()
|
|
self.frame:Hide()
|
|
end
|
|
|
|
-- setpoint
|
|
function PanelMetaFunctions:SetPoint(v1, v2, v3, v4, v5)
|
|
v1, v2, v3, v4, v5 = detailsFramework:CheckPoints (v1, v2, v3, v4, v5, self)
|
|
if (not v1) then
|
|
print("Invalid parameter for SetPoint")
|
|
return
|
|
end
|
|
return self.widget:SetPoint(v1, v2, v3, v4, v5)
|
|
end
|
|
|
|
-- sizes
|
|
function PanelMetaFunctions:SetSize(w, h)
|
|
if (w) then
|
|
self.frame:SetWidth(w)
|
|
end
|
|
if (h) then
|
|
self.frame:SetHeight(h)
|
|
end
|
|
end
|
|
|
|
-- clear
|
|
function PanelMetaFunctions:HideWidgets()
|
|
for widgetName, widgetSelf in pairs(self) do
|
|
if (type(widgetSelf) == "table" and widgetSelf.dframework) then
|
|
widgetSelf:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
-- backdrop
|
|
function PanelMetaFunctions:SetBackdrop(background, edge, tilesize, edgesize, tile, left, right, top, bottom)
|
|
|
|
if (type(background) == "boolean" and not background) then
|
|
return self.frame:SetBackdrop(nil)
|
|
|
|
elseif (type(background) == "table") then
|
|
self.frame:SetBackdrop(background)
|
|
|
|
else
|
|
local currentBackdrop = self.frame:GetBackdrop() or {edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border", bgFile="Interface\\DialogFrame\\UI-DialogBox-Background", tile=true, tileSize=16, edgeSize=16, insets={left=1, right=0, top=0, bottom=0}}
|
|
currentBackdrop.bgFile = background or currentBackdrop.bgFile
|
|
currentBackdrop.edgeFile = edgeFile or currentBackdrop.edgeFile
|
|
currentBackdrop.tileSize = tilesize or currentBackdrop.tileSize
|
|
currentBackdrop.edgeSize = edgesize or currentBackdrop.edgeSize
|
|
currentBackdrop.tile = tile or currentBackdrop.tile
|
|
currentBackdrop.insets.left = left or currentBackdrop.insets.left
|
|
currentBackdrop.insets.right = left or currentBackdrop.insets.right
|
|
currentBackdrop.insets.top = left or currentBackdrop.insets.top
|
|
currentBackdrop.insets.bottom = left or currentBackdrop.insets.bottom
|
|
self.frame:SetBackdrop(currentBackdrop)
|
|
end
|
|
end
|
|
|
|
-- backdropcolor
|
|
function PanelMetaFunctions:SetBackdropColor(color, arg2, arg3, arg4)
|
|
if (arg2) then
|
|
self.frame:SetBackdropColor(color, arg2, arg3, arg4 or 1)
|
|
else
|
|
local _value1, _value2, _value3, _value4 = detailsFramework:ParseColors(color)
|
|
self.frame:SetBackdropColor(_value1, _value2, _value3, _value4)
|
|
end
|
|
end
|
|
|
|
-- border color
|
|
function PanelMetaFunctions:SetBackdropBorderColor(color, arg2, arg3, arg4)
|
|
if (arg2) then
|
|
return self.frame:SetBackdropBorderColor(color, arg2, arg3, arg4)
|
|
end
|
|
local _value1, _value2, _value3, _value4 = detailsFramework:ParseColors(color)
|
|
self.frame:SetBackdropBorderColor(_value1, _value2, _value3, _value4)
|
|
end
|
|
|
|
-- tooltip
|
|
function PanelMetaFunctions:SetTooltip (tooltip)
|
|
if (tooltip) then
|
|
return rawset(self, "have_tooltip", tooltip)
|
|
else
|
|
return rawset(self, "have_tooltip", nil)
|
|
end
|
|
end
|
|
function PanelMetaFunctions:GetTooltip()
|
|
return rawget(self, "have_tooltip")
|
|
end
|
|
|
|
-- frame levels
|
|
function PanelMetaFunctions:GetFrameLevel()
|
|
return self.widget:GetFrameLevel()
|
|
end
|
|
function PanelMetaFunctions:SetFrameLevel(level, frame)
|
|
if (not frame) then
|
|
return self.widget:SetFrameLevel(level)
|
|
else
|
|
local framelevel = frame:GetFrameLevel (frame) + level
|
|
return self.widget:SetFrameLevel(framelevel)
|
|
end
|
|
end
|
|
|
|
-- frame stratas
|
|
function PanelMetaFunctions:SetFrameStrata()
|
|
return self.widget:GetFrameStrata()
|
|
end
|
|
function PanelMetaFunctions:SetFrameStrata(strata)
|
|
if (type(strata) == "table") then
|
|
self.widget:SetFrameStrata(strata:GetFrameStrata())
|
|
else
|
|
self.widget:SetFrameStrata(strata)
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
--scripts
|
|
|
|
local OnEnter = function(frame)
|
|
local capsule = frame.MyObject
|
|
local kill = capsule:RunHooksForWidget("OnEnter", frame, capsule)
|
|
if (kill) then
|
|
return
|
|
end
|
|
|
|
if (frame.MyObject.have_tooltip) then
|
|
GameCooltip2:Reset()
|
|
GameCooltip2:SetType ("tooltip")
|
|
GameCooltip2:SetColor ("main", "transparent")
|
|
GameCooltip2:AddLine(frame.MyObject.have_tooltip)
|
|
GameCooltip2:SetOwner(frame)
|
|
GameCooltip2:ShowCooltip()
|
|
end
|
|
end
|
|
|
|
local OnLeave = function(frame)
|
|
local capsule = frame.MyObject
|
|
local kill = capsule:RunHooksForWidget("OnLeave", frame, capsule)
|
|
if (kill) then
|
|
return
|
|
end
|
|
|
|
if (frame.MyObject.have_tooltip) then
|
|
GameCooltip2:ShowMe(false)
|
|
end
|
|
|
|
end
|
|
|
|
local OnHide = function(frame)
|
|
local capsule = frame.MyObject
|
|
local kill = capsule:RunHooksForWidget("OnHide", frame, capsule)
|
|
if (kill) then
|
|
return
|
|
end
|
|
end
|
|
|
|
local OnShow = function(frame)
|
|
local capsule = frame.MyObject
|
|
local kill = capsule:RunHooksForWidget("OnShow", frame, capsule)
|
|
if (kill) then
|
|
return
|
|
end
|
|
end
|
|
|
|
local OnMouseDown = function(frame, button)
|
|
local capsule = frame.MyObject
|
|
local kill = capsule:RunHooksForWidget("OnMouseDown", frame, button, capsule)
|
|
if (kill) then
|
|
return
|
|
end
|
|
|
|
if (frame.MyObject.container == UIParent) then
|
|
if (not frame.isLocked and frame:IsMovable()) then
|
|
frame.isMoving = true
|
|
frame:StartMoving()
|
|
end
|
|
|
|
elseif (not frame.MyObject.container.isLocked and frame.MyObject.container:IsMovable()) then
|
|
if (not frame.isLocked and frame:IsMovable()) then
|
|
frame.MyObject.container.isMoving = true
|
|
frame.MyObject.container:StartMoving()
|
|
end
|
|
end
|
|
|
|
|
|
end
|
|
|
|
local OnMouseUp = function(frame, button)
|
|
local capsule = frame.MyObject
|
|
local kill = capsule:RunHooksForWidget("OnMouseUp", frame, button, capsule)
|
|
if (kill) then
|
|
return
|
|
end
|
|
|
|
if (button == "RightButton" and frame.MyObject.rightButtonClose) then
|
|
frame.MyObject:Hide()
|
|
end
|
|
|
|
if (frame.MyObject.container == UIParent) then
|
|
if (frame.isMoving) then
|
|
frame:StopMovingOrSizing()
|
|
frame.isMoving = false
|
|
end
|
|
else
|
|
if (frame.MyObject.container.isMoving) then
|
|
frame.MyObject.container:StopMovingOrSizing()
|
|
frame.MyObject.container.isMoving = false
|
|
end
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------
|
|
--object constructor
|
|
function detailsFramework:CreatePanel (parent, w, h, backdrop, backdropcolor, bordercolor, member, name)
|
|
return detailsFramework:NewPanel(parent, parent, name, member, w, h, backdrop, backdropcolor, bordercolor)
|
|
end
|
|
|
|
function detailsFramework:NewPanel(parent, container, name, member, w, h, backdrop, backdropcolor, bordercolor)
|
|
|
|
if (not name) then
|
|
name = "DetailsFrameworkPanelNumber" .. detailsFramework.PanelCounter
|
|
detailsFramework.PanelCounter = detailsFramework.PanelCounter + 1
|
|
|
|
elseif (not parent) then
|
|
parent = UIParent
|
|
end
|
|
if (not container) then
|
|
container = parent
|
|
end
|
|
|
|
if (name:find("$parent")) then
|
|
name = name:gsub("$parent", parent:GetName())
|
|
end
|
|
|
|
local PanelObject = {type = "panel", dframework = true}
|
|
|
|
if (member) then
|
|
parent [member] = PanelObject
|
|
end
|
|
|
|
if (parent.dframework) then
|
|
parent = parent.widget
|
|
end
|
|
if (container.dframework) then
|
|
container = container.widget
|
|
end
|
|
|
|
--default members:
|
|
--misc
|
|
PanelObject.is_locked = true
|
|
PanelObject.container = container
|
|
PanelObject.rightButtonClose = false
|
|
|
|
PanelObject.frame = CreateFrame("frame", name, parent,"BackdropTemplate")
|
|
PanelObject.frame:SetSize(100, 100)
|
|
PanelObject.frame.Gradient = {
|
|
["OnEnter"] = {0.3, 0.3, 0.3, 0.5},
|
|
["OnLeave"] = {0.9, 0.7, 0.7, 1}
|
|
}
|
|
PanelObject.frame:SetBackdrop({bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", edgeSize = 10, tileSize = 64, tile = true})
|
|
|
|
PanelObject.widget = PanelObject.frame
|
|
PanelObject.frame.MyObject = PanelObject
|
|
|
|
if (not APIFrameFunctions) then
|
|
APIFrameFunctions = {}
|
|
local idx = getmetatable(PanelObject.frame).__index
|
|
for funcName, funcAddress in pairs(idx) do
|
|
if (not PanelMetaFunctions [funcName]) then
|
|
PanelMetaFunctions [funcName] = function(object, ...)
|
|
local x = loadstring ( "return _G['"..object.frame:GetName().."']:"..funcName.."(...)")
|
|
return x (...)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
PanelObject.frame:SetWidth(w or 100)
|
|
PanelObject.frame:SetHeight(h or 100)
|
|
|
|
PanelObject.HookList = {
|
|
OnEnter = {},
|
|
OnLeave = {},
|
|
OnHide = {},
|
|
OnShow = {},
|
|
OnMouseDown = {},
|
|
OnMouseUp = {},
|
|
}
|
|
|
|
--hooks
|
|
PanelObject.frame:SetScript("OnEnter", OnEnter)
|
|
PanelObject.frame:SetScript("OnLeave", OnLeave)
|
|
PanelObject.frame:SetScript("OnHide", OnHide)
|
|
PanelObject.frame:SetScript("OnShow", OnShow)
|
|
PanelObject.frame:SetScript("OnMouseDown", OnMouseDown)
|
|
PanelObject.frame:SetScript("OnMouseUp", OnMouseUp)
|
|
|
|
setmetatable(PanelObject, PanelMetaFunctions)
|
|
|
|
if (backdrop) then
|
|
PanelObject:SetBackdrop(backdrop)
|
|
elseif (type(backdrop) == "boolean") then
|
|
PanelObject.frame:SetBackdrop(nil)
|
|
end
|
|
|
|
if (backdropcolor) then
|
|
PanelObject:SetBackdropColor(backdropcolor)
|
|
end
|
|
|
|
if (bordercolor) then
|
|
PanelObject:SetBackdropBorderColor(bordercolor)
|
|
end
|
|
|
|
return PanelObject
|
|
end
|
|
|
|
------------fill panel
|
|
|
|
local button_on_enter = function(self)
|
|
self.MyObject._icon:SetBlendMode("ADD")
|
|
if (self.MyObject.onenter_func) then
|
|
pcall(self.MyObject.onenter_func, self.MyObject)
|
|
end
|
|
end
|
|
local button_on_leave = function(self)
|
|
self.MyObject._icon:SetBlendMode("BLEND")
|
|
if (self.MyObject.onleave_func) then
|
|
pcall(self.MyObject.onleave_func, self.MyObject)
|
|
end
|
|
end
|
|
|
|
local add_row = function(self, t, need_update)
|
|
local index = #self.rows+1
|
|
|
|
local thisrow = detailsFramework:NewPanel(self, self, "$parentHeader_" .. self._name .. index, nil, 1, 20)
|
|
thisrow.backdrop = {bgFile = [[Interface\Tooltips\UI-Tooltip-Background]]}
|
|
thisrow.color = {.3, .3, .3, .9}
|
|
thisrow.type = t.type
|
|
thisrow.func = t.func
|
|
thisrow.name = t.name
|
|
thisrow.notext = t.notext
|
|
thisrow.icon = t.icon
|
|
thisrow.iconalign = t.iconalign
|
|
|
|
thisrow.hidden = t.hidden or false
|
|
|
|
thisrow.onenter = t.onenter
|
|
thisrow.onleave = t.onleave
|
|
|
|
local text = detailsFramework:NewLabel(thisrow, nil, self._name .. "$parentLabel" .. index, "text")
|
|
text:SetPoint("left", thisrow, "left", 2, 0)
|
|
text:SetText(t.name)
|
|
|
|
table.insert(self._raw_rows, t)
|
|
table.insert(self.rows, thisrow)
|
|
|
|
if (need_update) then
|
|
self:AlignRows()
|
|
end
|
|
end
|
|
|
|
local align_rows = function(self)
|
|
|
|
local rows_shown = 0
|
|
for index, row in ipairs(self.rows) do
|
|
if (not row.hidden) then
|
|
rows_shown = rows_shown + 1
|
|
end
|
|
end
|
|
|
|
local cur_width = 1
|
|
local row_width = self._width / max(rows_shown, 0.0001)
|
|
|
|
|
|
local sindex = 1
|
|
|
|
wipe (self._anchors)
|
|
|
|
for index, row in ipairs(self.rows) do
|
|
if (not row.hidden) then
|
|
if (self._autowidth) then
|
|
if (self._raw_rows [index].width) then
|
|
row.width = self._raw_rows [index].width
|
|
else
|
|
row.width = row_width
|
|
end
|
|
row:SetPoint("topleft", self, "topleft", cur_width, -1)
|
|
table.insert(self._anchors, cur_width)
|
|
cur_width = cur_width + row_width + 1
|
|
else
|
|
row:SetPoint("topleft", self, "topleft", cur_width, -1)
|
|
row.width = self._raw_rows [index].width
|
|
table.insert(self._anchors, cur_width)
|
|
cur_width = cur_width + self._raw_rows [index].width + 1
|
|
end
|
|
|
|
row:Show()
|
|
|
|
local rowType = row.type
|
|
|
|
if (rowType == "text") then
|
|
for i = 1, #self.scrollframe.lines do
|
|
local line = self.scrollframe.lines [i]
|
|
local text = tremove(line.text_available)
|
|
if (not text) then
|
|
self:CreateRowText (line)
|
|
text = tremove(line.text_available)
|
|
end
|
|
table.insert(line.text_inuse, text)
|
|
text:SetPoint("left", line, "left", self._anchors [#self._anchors], 0)
|
|
text:SetWidth(row.width)
|
|
|
|
detailsFramework:SetFontSize(text, row.textsize or 10)
|
|
text:SetJustifyH(row.textalign or "left")
|
|
end
|
|
elseif (rowType == "entry") then
|
|
for i = 1, #self.scrollframe.lines do
|
|
local line = self.scrollframe.lines [i]
|
|
local entry = tremove(line.entry_available)
|
|
if (not entry) then
|
|
self:CreateRowEntry (line)
|
|
entry = tremove(line.entry_available)
|
|
end
|
|
table.insert(line.entry_inuse, entry)
|
|
entry:SetPoint("left", line, "left", self._anchors [#self._anchors], 0)
|
|
if (sindex == rows_shown) then
|
|
entry:SetWidth(row.width - 25)
|
|
else
|
|
entry:SetWidth(row.width)
|
|
end
|
|
entry.func = row.func
|
|
|
|
entry.onenter_func = nil
|
|
entry.onleave_func = nil
|
|
|
|
if (row.onenter) then
|
|
entry.onenter_func = row.onenter
|
|
end
|
|
if (row.onleave) then
|
|
entry.onleave_func = row.onleave
|
|
end
|
|
end
|
|
|
|
elseif (rowType == "checkbox") then
|
|
for i = 1, #self.scrollframe.lines do
|
|
local line = self.scrollframe.lines [i]
|
|
local checkbox = tremove(line.checkbox_available)
|
|
if (not checkbox) then
|
|
self:CreateCheckbox (line)
|
|
checkbox = tremove(line.checkbox_available)
|
|
end
|
|
|
|
table.insert(line.checkbox_inuse, checkbox)
|
|
|
|
checkbox:SetPoint("left", line, "left", self._anchors [#self._anchors] + ((row.width - 20) / 2), 0)
|
|
if (sindex == rows_shown) then
|
|
checkbox:SetWidth(20)
|
|
--checkbox:SetWidth(row.width - 25)
|
|
else
|
|
checkbox:SetWidth(20)
|
|
end
|
|
|
|
checkbox.onenter_func = nil
|
|
checkbox.onleave_func = nil
|
|
end
|
|
|
|
elseif (rowType == "button") then
|
|
for i = 1, #self.scrollframe.lines do
|
|
local line = self.scrollframe.lines [i]
|
|
local button = tremove(line.button_available)
|
|
if (not button) then
|
|
self:CreateRowButton (line)
|
|
button = tremove(line.button_available)
|
|
end
|
|
table.insert(line.button_inuse, button)
|
|
button:SetPoint("left", line, "left", self._anchors [#self._anchors], 0)
|
|
if (sindex == rows_shown) then
|
|
button:SetWidth(row.width - 25)
|
|
else
|
|
button:SetWidth(row.width)
|
|
end
|
|
|
|
if (row.icon) then
|
|
button._icon.texture = row.icon
|
|
button._icon:ClearAllPoints()
|
|
if (row.iconalign) then
|
|
if (row.iconalign == "center") then
|
|
button._icon:SetPoint("center", button, "center")
|
|
elseif (row.iconalign == "right") then
|
|
button._icon:SetPoint("right", button, "right")
|
|
end
|
|
else
|
|
button._icon:SetPoint("left", button, "left")
|
|
end
|
|
end
|
|
|
|
if (row.name and not row.notext) then
|
|
button._text:SetPoint("left", button._icon, "right", 2, 0)
|
|
button._text.text = row.name
|
|
end
|
|
|
|
button.onenter_func = nil
|
|
button.onleave_func = nil
|
|
|
|
if (row.onenter) then
|
|
button.onenter_func = row.onenter
|
|
end
|
|
if (row.onleave) then
|
|
button.onleave_func = row.onleave
|
|
end
|
|
|
|
end
|
|
elseif (rowType == "icon") then
|
|
for i = 1, #self.scrollframe.lines do
|
|
local line = self.scrollframe.lines [i]
|
|
local icon = tremove(line.icon_available)
|
|
if (not icon) then
|
|
self:CreateRowIcon (line)
|
|
icon = tremove(line.icon_available)
|
|
end
|
|
table.insert(line.icon_inuse, icon)
|
|
icon:SetPoint("left", line, "left", self._anchors [#self._anchors] + ( ((row.width or 22) - 22) / 2), 0)
|
|
icon.func = row.func
|
|
end
|
|
|
|
elseif (rowType == "texture") then
|
|
for i = 1, #self.scrollframe.lines do
|
|
local line = self.scrollframe.lines [i]
|
|
local texture = tremove(line.texture_available)
|
|
if (not texture) then
|
|
self:CreateRowTexture (line)
|
|
texture = tremove(line.texture_available)
|
|
end
|
|
table.insert(line.texture_inuse, texture)
|
|
texture:SetPoint("left", line, "left", self._anchors [#self._anchors] + ( ((row.width or 22) - 22) / 2), 0)
|
|
end
|
|
|
|
end
|
|
|
|
sindex = sindex + 1
|
|
else
|
|
row:Hide()
|
|
end
|
|
end
|
|
|
|
if (#self.rows > 0) then
|
|
if (self._autowidth) then
|
|
self.rows [#self.rows]:SetWidth(row_width - rows_shown + 1)
|
|
else
|
|
self.rows [#self.rows]:SetWidth(self._raw_rows [rows_shown].width - rows_shown + 1)
|
|
end
|
|
end
|
|
|
|
self.showing_amt = rows_shown
|
|
end
|
|
|
|
local update_rows = function(self, updated_rows)
|
|
|
|
for i = 1, #updated_rows do
|
|
local t = updated_rows [i]
|
|
local raw = self._raw_rows [i]
|
|
|
|
if (not raw) then
|
|
self:AddRow (t)
|
|
else
|
|
raw.name = t.name
|
|
raw.hidden = t.hidden or false
|
|
raw.textsize = t.textsize
|
|
raw.textalign = t.textalign
|
|
|
|
local widget = self.rows [i]
|
|
widget.name = t.name
|
|
widget.textsize = t.textsize
|
|
widget.textalign = t.textalign
|
|
widget.hidden = t.hidden or false
|
|
|
|
--
|
|
widget.onenter = t.onenter
|
|
widget.onleave = t.onleave
|
|
--
|
|
|
|
widget.text:SetText(t.name)
|
|
detailsFramework:SetFontSize(widget.text, raw.textsize or 10)
|
|
widget.text:SetJustifyH(raw.textalign or "left")
|
|
end
|
|
end
|
|
|
|
for i = #updated_rows+1, #self._raw_rows do
|
|
local raw = self._raw_rows [i]
|
|
local widget = self.rows [i]
|
|
raw.hidden = true
|
|
widget.hidden = true
|
|
end
|
|
|
|
for index, row in ipairs(self.scrollframe.lines) do
|
|
for i = #row.text_inuse, 1, -1 do
|
|
table.insert(row.text_available, tremove(row.text_inuse, i))
|
|
end
|
|
for i = 1, #row.text_available do
|
|
row.text_available[i]:Hide()
|
|
end
|
|
|
|
for i = #row.entry_inuse, 1, -1 do
|
|
table.insert(row.entry_available, tremove(row.entry_inuse, i))
|
|
end
|
|
for i = 1, #row.entry_available do
|
|
row.entry_available[i]:Hide()
|
|
end
|
|
|
|
for i = #row.button_inuse, 1, -1 do
|
|
table.insert(row.button_available, tremove(row.button_inuse, i))
|
|
end
|
|
for i = 1, #row.button_available do
|
|
row.button_available[i]:Hide()
|
|
end
|
|
|
|
for i = #row.checkbox_inuse, 1, -1 do
|
|
table.insert(row.checkbox_available, tremove(row.checkbox_inuse, i))
|
|
end
|
|
for i = 1, #row.checkbox_available do
|
|
row.checkbox_available[i]:Hide()
|
|
end
|
|
|
|
for i = #row.icon_inuse, 1, -1 do
|
|
table.insert(row.icon_available, tremove(row.icon_inuse, i))
|
|
end
|
|
for i = 1, #row.icon_available do
|
|
row.icon_available[i]:Hide()
|
|
end
|
|
|
|
for i = #row.texture_inuse, 1, -1 do
|
|
table.insert(row.texture_available, tremove(row.texture_inuse, i))
|
|
end
|
|
for i = 1, #row.texture_available do
|
|
row.texture_available[i]:Hide()
|
|
end
|
|
end
|
|
|
|
self.current_header = updated_rows
|
|
|
|
self:AlignRows()
|
|
|
|
end
|
|
|
|
local create_panel_text = function(self, row)
|
|
row.text_total = row.text_total + 1
|
|
local text = detailsFramework:NewLabel(row, nil, self._name .. "$parentLabel" .. row.text_total, "text" .. row.text_total)
|
|
table.insert(row.text_available, text)
|
|
end
|
|
|
|
local create_panel_entry = function(self, row)
|
|
row.entry_total = row.entry_total + 1
|
|
local editbox = detailsFramework:NewTextEntry(row, nil, "$parentEntry" .. row.entry_total, "entry", 120, 20)
|
|
editbox.align = "left"
|
|
|
|
editbox:SetHook("OnEnterPressed", function()
|
|
editbox.widget.focuslost = true
|
|
editbox:ClearFocus()
|
|
editbox.func (editbox.index, editbox.text)
|
|
return true
|
|
end)
|
|
|
|
editbox:SetHook("OnEnter", function()
|
|
if (editbox.onenter_func) then
|
|
pcall(editbox.onenter_func, editbox)
|
|
end
|
|
end)
|
|
editbox:SetHook("OnLeave", function()
|
|
if (editbox.onleave_func) then
|
|
pcall(editbox.onleave_func, editbox)
|
|
end
|
|
end)
|
|
|
|
editbox.editbox.current_bordercolor = {1, 1, 1, 0.1}
|
|
|
|
editbox:SetTemplate(detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
|
editbox:SetBackdropColor(.2, .2, .2, 0.7)
|
|
|
|
table.insert(row.entry_available, editbox)
|
|
end
|
|
|
|
local create_panel_checkbox = function(self, row)
|
|
--row.checkbox_available
|
|
row.checkbox_total = row.checkbox_total + 1
|
|
|
|
local switch = detailsFramework:NewSwitch (row, nil, "$parentCheckBox" .. row.checkbox_total, nil, 20, 20, nil, nil, false)
|
|
switch:SetAsCheckBox()
|
|
switch:SetTemplate(detailsFramework:GetTemplate("switch", "OPTIONS_CHECKBOX_TEMPLATE"))
|
|
|
|
table.insert(row.checkbox_available, switch)
|
|
end
|
|
|
|
local create_panel_button = function(self, row)
|
|
row.button_total = row.button_total + 1
|
|
local button = detailsFramework:NewButton(row, nil, "$parentButton" .. row.button_total, "button" .. row.button_total, 120, 20)
|
|
|
|
--create icon and the text
|
|
local icon = detailsFramework:NewImage(button, nil, 20, 20)
|
|
local text = detailsFramework:NewLabel(button)
|
|
|
|
button._icon = icon
|
|
button._text = text
|
|
|
|
button:SetHook("OnEnter", button_on_enter)
|
|
button:SetHook("OnLeave", button_on_leave)
|
|
|
|
table.insert(row.button_available, button)
|
|
end
|
|
|
|
local icon_onclick = function(texture, iconbutton)
|
|
iconbutton._icon.texture = texture
|
|
iconbutton.func (iconbutton.index, texture)
|
|
end
|
|
|
|
local create_panel_icon = function(self, row)
|
|
row.icon_total = row.icon_total + 1
|
|
local iconbutton = detailsFramework:NewButton(row, nil, "$parentIconButton" .. row.icon_total, "iconbutton", 22, 20)
|
|
|
|
iconbutton:SetHook("OnEnter", button_on_enter)
|
|
iconbutton:SetHook("OnLeave", button_on_leave)
|
|
|
|
iconbutton:SetHook("OnMouseUp", function()
|
|
detailsFramework:IconPick (icon_onclick, true, iconbutton)
|
|
return true
|
|
end)
|
|
|
|
local icon = detailsFramework:NewImage(iconbutton, nil, 20, 20, "artwork", nil, "_icon", "$parentIcon" .. row.icon_total)
|
|
iconbutton._icon = icon
|
|
|
|
icon:SetPoint("center", iconbutton, "center", 0, 0)
|
|
|
|
table.insert(row.icon_available, iconbutton)
|
|
end
|
|
|
|
local create_panel_texture = function(self, row)
|
|
row.texture_total = row.texture_total + 1
|
|
local texture = detailsFramework:NewImage(row, nil, 20, 20, "artwork", nil, "_icon" .. row.texture_total, "$parentIcon" .. row.texture_total)
|
|
table.insert(row.texture_available, texture)
|
|
end
|
|
|
|
local set_fill_function = function(self, func)
|
|
self._fillfunc = func
|
|
end
|
|
local set_total_function = function(self, func)
|
|
self._totalfunc = func
|
|
end
|
|
local drop_header_function = function(self)
|
|
wipe (self.rows)
|
|
end
|
|
|
|
local fillpanel_update_size = function(self, elapsed)
|
|
local panel = self.MyObject
|
|
|
|
panel._width = panel:GetWidth()
|
|
panel._height = panel:GetHeight()
|
|
|
|
panel:UpdateRowAmount()
|
|
if (panel.current_header) then
|
|
update_rows (panel, panel.current_header)
|
|
end
|
|
panel:Refresh()
|
|
|
|
self:SetScript("OnUpdate", nil)
|
|
end
|
|
|
|
-- ~fillpanel
|
|
--alias
|
|
function detailsFramework:CreateFillPanel(parent, rows, w, h, total_lines, fill_row, autowidth, options, member, name)
|
|
return detailsFramework:NewFillPanel(parent, rows, name, member, w, h, total_lines, fill_row, autowidth, options)
|
|
end
|
|
|
|
function detailsFramework:NewFillPanel(parent, rows, name, member, w, h, total_lines, fill_row, autowidth, options)
|
|
local panel = detailsFramework:NewPanel(parent, parent, name, member, w, h)
|
|
panel.backdrop = nil
|
|
|
|
options = options or {rowheight = 20}
|
|
panel.rows = {}
|
|
|
|
panel.AddRow = add_row
|
|
panel.AlignRows = align_rows
|
|
panel.UpdateRows = update_rows
|
|
panel.CreateRowText = create_panel_text
|
|
panel.CreateRowEntry = create_panel_entry
|
|
panel.CreateRowButton = create_panel_button
|
|
panel.CreateCheckbox = create_panel_checkbox
|
|
panel.CreateRowIcon = create_panel_icon
|
|
panel.CreateRowTexture = create_panel_texture
|
|
panel.SetFillFunction = set_fill_function
|
|
panel.SetTotalFunction = set_total_function
|
|
panel.DropHeader = drop_header_function
|
|
|
|
panel._name = name
|
|
panel._width = w
|
|
panel._height = h
|
|
panel._raw_rows = {}
|
|
panel._anchors = {}
|
|
panel._fillfunc = fill_row
|
|
panel._totalfunc = total_lines
|
|
panel._autowidth = autowidth
|
|
|
|
panel:SetScript("OnSizeChanged", function()
|
|
panel:SetScript("OnUpdate", fillpanel_update_size)
|
|
end)
|
|
|
|
for index, t in ipairs(rows) do
|
|
panel.AddRow(panel, t)
|
|
end
|
|
|
|
local refresh_fillbox = function(self)
|
|
local offset = FauxScrollFrame_GetOffset(self)
|
|
local filled_lines = panel._totalfunc(panel)
|
|
|
|
for index = 1, #self.lines do
|
|
local row = self.lines [index]
|
|
if (index <= filled_lines) then
|
|
|
|
local real_index = index + offset
|
|
local results = panel._fillfunc (real_index, panel)
|
|
|
|
if (results and results [1]) then
|
|
row:Show()
|
|
|
|
local text, entry, button, icon, texture, checkbox = 1, 1, 1, 1, 1, 1
|
|
|
|
for index, t in ipairs(panel.rows) do
|
|
if (not t.hidden) then
|
|
if (t.type == "text") then
|
|
local fontstring = row.text_inuse [text]
|
|
text = text + 1
|
|
fontstring:SetText(results [index])
|
|
fontstring.index = real_index
|
|
fontstring:Show()
|
|
|
|
elseif (t.type == "entry") then
|
|
local entrywidget = row.entry_inuse [entry]
|
|
entry = entry + 1
|
|
entrywidget.index = real_index
|
|
|
|
if (type(results [index]) == "table") then
|
|
entrywidget:SetText(results [index].text)
|
|
entrywidget.id = results [index].id
|
|
entrywidget.data1 = results [index].data1
|
|
entrywidget.data2 = results [index].data2
|
|
else
|
|
entrywidget:SetText(results [index])
|
|
end
|
|
|
|
entrywidget:SetCursorPosition(0)
|
|
|
|
entrywidget:Show()
|
|
|
|
elseif (t.type == "checkbox") then
|
|
local checkboxwidget = row.checkbox_inuse [button]
|
|
checkbox = checkbox + 1
|
|
checkboxwidget.index = real_index
|
|
checkboxwidget:SetValue(results [index])
|
|
|
|
local func = function()
|
|
t.func (real_index, index)
|
|
panel:Refresh()
|
|
end
|
|
checkboxwidget.OnSwitch = func
|
|
|
|
elseif (t.type == "button") then
|
|
local buttonwidget = row.button_inuse [button]
|
|
button = button + 1
|
|
buttonwidget.index = real_index
|
|
|
|
if (type(results [index]) == "table") then
|
|
if (results [index].text) then
|
|
buttonwidget:SetText(results [index].text)
|
|
end
|
|
|
|
if (results [index].icon) then
|
|
buttonwidget._icon:SetTexture(results [index].icon)
|
|
end
|
|
|
|
if (results [index].func) then
|
|
local func = function()
|
|
t.func (real_index, results [index].value)
|
|
panel:Refresh()
|
|
end
|
|
buttonwidget:SetClickFunction(func)
|
|
else
|
|
local func = function()
|
|
t.func (real_index, index)
|
|
panel:Refresh()
|
|
end
|
|
buttonwidget:SetClickFunction(func)
|
|
end
|
|
|
|
buttonwidget.id = results [index].id
|
|
buttonwidget.data1 = results [index].data1
|
|
buttonwidget.data2 = results [index].data2
|
|
|
|
else
|
|
local func = function()
|
|
t.func (real_index, index)
|
|
panel:Refresh()
|
|
end
|
|
buttonwidget:SetClickFunction(func)
|
|
buttonwidget:SetText(results [index])
|
|
end
|
|
|
|
buttonwidget:Show()
|
|
|
|
elseif (t.type == "icon") then
|
|
local iconwidget = row.icon_inuse [icon]
|
|
icon = icon + 1
|
|
|
|
iconwidget.line = index
|
|
iconwidget.index = real_index
|
|
|
|
if (type(results [index]) == "string") then
|
|
local result = results [index]:gsub(".-%\\", "")
|
|
iconwidget._icon.texture = results [index]
|
|
iconwidget._icon:SetTexCoord(0.1, .9, 0.1, .9)
|
|
|
|
elseif (type(results [index]) == "table") then
|
|
iconwidget._icon:SetTexture(results [index].texture)
|
|
|
|
local textCoord = results [index].texcoord
|
|
if (textCoord) then
|
|
iconwidget._icon:SetTexCoord(unpack(textCoord))
|
|
else
|
|
iconwidget._icon:SetTexCoord(0.1, .9, 0.1, .9)
|
|
end
|
|
|
|
local color = results [index].color
|
|
if (color) then
|
|
local r, g, b, a = detailsFramework:ParseColors(color)
|
|
iconwidget._icon:SetVertexColor(r, g, b, a)
|
|
else
|
|
iconwidget._icon:SetVertexColor(1, 1, 1, 1)
|
|
end
|
|
else
|
|
iconwidget._icon:SetTexture(results [index])
|
|
iconwidget._icon:SetTexCoord(0.1, .9, 0.1, .9)
|
|
end
|
|
|
|
iconwidget:Show()
|
|
|
|
elseif (t.type == "texture") then
|
|
local texturewidget = row.texture_inuse [texture]
|
|
texture = texture + 1
|
|
|
|
texturewidget.line = index
|
|
texturewidget.index = real_index
|
|
|
|
if (type(results [index]) == "string") then
|
|
local result = results [index]:gsub(".-%\\", "")
|
|
texturewidget.texture = results [index]
|
|
|
|
elseif (type(results [index]) == "table") then
|
|
texturewidget:SetTexture(results [index].texture)
|
|
|
|
local textCoord = results [index].texcoord
|
|
if (textCoord) then
|
|
texturewidget:SetTexCoord(unpack(textCoord))
|
|
else
|
|
texturewidget:SetTexCoord(0, 1, 0, 1)
|
|
end
|
|
|
|
local color = results [index].color
|
|
if (color) then
|
|
local r, g, b, a = detailsFramework:ParseColors(color)
|
|
texturewidget:SetVertexColor(r, g, b, a)
|
|
else
|
|
texturewidget:SetVertexColor(1, 1, 1, 1)
|
|
end
|
|
|
|
else
|
|
texturewidget:SetTexture(results [index])
|
|
end
|
|
|
|
texturewidget:Show()
|
|
end
|
|
end
|
|
end
|
|
|
|
else
|
|
row:Hide()
|
|
end
|
|
else
|
|
row:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
function panel:Refresh()
|
|
if (type(panel._totalfunc) == "boolean") then
|
|
--not yet initialized
|
|
return
|
|
end
|
|
local filled_lines = panel._totalfunc (panel)
|
|
local scroll_total_lines = #panel.scrollframe.lines
|
|
local line_height = options.rowheight
|
|
refresh_fillbox (panel.scrollframe)
|
|
FauxScrollFrame_Update (panel.scrollframe, filled_lines, scroll_total_lines, line_height)
|
|
panel.scrollframe:Show()
|
|
end
|
|
|
|
local scrollframe = CreateFrame("scrollframe", name .. "Scroll", panel.widget, "FauxScrollFrameTemplate", "BackdropTemplate")
|
|
scrollframe:SetScript("OnVerticalScroll", function(self, offset) FauxScrollFrame_OnVerticalScroll (self, offset, 20, panel.Refresh) end)
|
|
scrollframe:SetPoint("topleft", panel.widget, "topleft", 0, -21)
|
|
scrollframe:SetPoint("topright", panel.widget, "topright", -23, -21)
|
|
scrollframe:SetPoint("bottomleft", panel.widget, "bottomleft")
|
|
scrollframe:SetPoint("bottomright", panel.widget, "bottomright", -23, 0)
|
|
scrollframe:SetSize(w, h)
|
|
panel.scrollframe = scrollframe
|
|
scrollframe.lines = {}
|
|
|
|
detailsFramework:ReskinSlider(scrollframe)
|
|
|
|
--create lines
|
|
function panel:UpdateRowAmount()
|
|
local size = options.rowheight
|
|
local amount = math.floor(((panel._height-21) / size))
|
|
|
|
for i = #scrollframe.lines+1, amount do
|
|
local row = CreateFrame("frame", panel:GetName() .. "Row_" .. i, panel.widget,"BackdropTemplate")
|
|
row:SetSize(1, size)
|
|
row.color = {1, 1, 1, .2}
|
|
|
|
row:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]]})
|
|
|
|
if (i%2 == 0) then
|
|
row:SetBackdropColor(.5, .5, .5, 0.2)
|
|
else
|
|
row:SetBackdropColor(1, 1, 1, 0.00)
|
|
end
|
|
|
|
row:SetPoint("topleft", scrollframe, "topleft", 0, (i-1) * size * -1)
|
|
row:SetPoint("topright", scrollframe, "topright", 0, (i-1) * size * -1)
|
|
table.insert(scrollframe.lines, row)
|
|
|
|
row.text_available = {}
|
|
row.text_inuse = {}
|
|
row.text_total = 0
|
|
|
|
row.entry_available = {}
|
|
row.entry_inuse = {}
|
|
row.entry_total = 0
|
|
|
|
row.button_available = {}
|
|
row.button_inuse = {}
|
|
row.button_total = 0
|
|
|
|
row.checkbox_available = {}
|
|
row.checkbox_inuse = {}
|
|
row.checkbox_total = 0
|
|
|
|
row.icon_available = {}
|
|
row.icon_inuse = {}
|
|
row.icon_total = 0
|
|
|
|
row.texture_available = {}
|
|
row.texture_inuse = {}
|
|
row.texture_total = 0
|
|
end
|
|
end
|
|
panel:UpdateRowAmount()
|
|
|
|
panel.AlignRows (panel)
|
|
|
|
return panel
|
|
end
|
|
|
|
|
|
------------color pick
|
|
local color_pick_func = function()
|
|
local r, g, b = ColorPickerFrame:GetColorRGB()
|
|
local a = OpacitySliderFrame:GetValue()
|
|
ColorPickerFrame:dcallback (r, g, b, a, ColorPickerFrame.dframe)
|
|
end
|
|
local color_pick_func_cancel = function()
|
|
ColorPickerFrame:SetColorRGB (unpack(ColorPickerFrame.previousValues))
|
|
local r, g, b = ColorPickerFrame:GetColorRGB()
|
|
local a = OpacitySliderFrame:GetValue()
|
|
ColorPickerFrame:dcallback (r, g, b, a, ColorPickerFrame.dframe)
|
|
end
|
|
|
|
function detailsFramework:ColorPick (frame, r, g, b, alpha, callback)
|
|
|
|
ColorPickerFrame:ClearAllPoints()
|
|
ColorPickerFrame:SetPoint("bottomleft", frame, "topright", 0, 0)
|
|
|
|
ColorPickerFrame.dcallback = callback
|
|
ColorPickerFrame.dframe = frame
|
|
|
|
ColorPickerFrame.func = color_pick_func
|
|
ColorPickerFrame.opacityFunc = color_pick_func
|
|
ColorPickerFrame.cancelFunc = color_pick_func_cancel
|
|
|
|
ColorPickerFrame.opacity = alpha
|
|
ColorPickerFrame.hasOpacity = alpha and true
|
|
|
|
ColorPickerFrame.previousValues = {r, g, b}
|
|
ColorPickerFrame:SetParent(UIParent)
|
|
ColorPickerFrame:SetFrameStrata("tooltip")
|
|
ColorPickerFrame:SetColorRGB (r, g, b)
|
|
ColorPickerFrame:Show()
|
|
|
|
end
|
|
|
|
------------icon pick
|
|
function detailsFramework:IconPick (callback, close_when_select, param1, param2)
|
|
|
|
if (not detailsFramework.IconPickFrame) then
|
|
|
|
local string_lower = string.lower
|
|
|
|
detailsFramework.IconPickFrame = CreateFrame("frame", "DetailsFrameworkIconPickFrame", UIParent, "BackdropTemplate")
|
|
table.insert(UISpecialFrames, "DetailsFrameworkIconPickFrame")
|
|
detailsFramework.IconPickFrame:SetFrameStrata("FULLSCREEN")
|
|
|
|
detailsFramework.IconPickFrame:SetPoint("center", UIParent, "center")
|
|
detailsFramework.IconPickFrame:SetWidth(416)
|
|
detailsFramework.IconPickFrame:SetHeight(350)
|
|
detailsFramework.IconPickFrame:EnableMouse(true)
|
|
detailsFramework.IconPickFrame:SetMovable(true)
|
|
|
|
detailsFramework:CreateTitleBar (detailsFramework.IconPickFrame, "Details! Framework Icon Picker")
|
|
|
|
detailsFramework.IconPickFrame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
|
detailsFramework.IconPickFrame:SetBackdropBorderColor(0, 0, 0)
|
|
detailsFramework.IconPickFrame:SetBackdropColor(24/255, 24/255, 24/255, .8)
|
|
detailsFramework.IconPickFrame:SetFrameLevel(5000)
|
|
|
|
detailsFramework.IconPickFrame:SetScript("OnMouseDown", function(self)
|
|
if (not self.isMoving) then
|
|
detailsFramework.IconPickFrame:StartMoving()
|
|
self.isMoving = true
|
|
end
|
|
end)
|
|
|
|
detailsFramework.IconPickFrame:SetScript("OnMouseUp", function(self)
|
|
if (self.isMoving) then
|
|
detailsFramework.IconPickFrame:StopMovingOrSizing()
|
|
self.isMoving = nil
|
|
end
|
|
end)
|
|
|
|
detailsFramework.IconPickFrame.emptyFunction = function() end
|
|
detailsFramework.IconPickFrame.callback = detailsFramework.IconPickFrame.emptyFunction
|
|
|
|
detailsFramework.IconPickFrame.preview = CreateFrame("frame", nil, UIParent, "BackdropTemplate")
|
|
detailsFramework.IconPickFrame.preview:SetFrameStrata("tooltip")
|
|
detailsFramework.IconPickFrame.preview:SetFrameLevel(6001)
|
|
detailsFramework.IconPickFrame.preview:SetSize(76, 76)
|
|
|
|
local preview_image_bg = detailsFramework:NewImage(detailsFramework.IconPickFrame.preview, nil, 76, 76)
|
|
preview_image_bg:SetDrawLayer("background", 0)
|
|
preview_image_bg:SetAllPoints(detailsFramework.IconPickFrame.preview)
|
|
preview_image_bg:SetColorTexture(0, 0, 0)
|
|
|
|
local preview_image = detailsFramework:NewImage(detailsFramework.IconPickFrame.preview, nil, 76, 76)
|
|
preview_image:SetAllPoints(detailsFramework.IconPickFrame.preview)
|
|
|
|
detailsFramework.IconPickFrame.preview.icon = preview_image
|
|
detailsFramework.IconPickFrame.preview:Hide()
|
|
|
|
--serach
|
|
detailsFramework.IconPickFrame.searchLabel = detailsFramework:NewLabel(detailsFramework.IconPickFrame, nil, "$parentSearchBoxLabel", nil, "Search:")
|
|
detailsFramework.IconPickFrame.searchLabel:SetPoint("topleft", detailsFramework.IconPickFrame, "topleft", 12, -36)
|
|
detailsFramework.IconPickFrame.searchLabel:SetTemplate(detailsFramework:GetTemplate("font", "ORANGE_FONT_TEMPLATE"))
|
|
detailsFramework.IconPickFrame.searchLabel.fontsize = 12
|
|
|
|
detailsFramework.IconPickFrame.search = detailsFramework:NewTextEntry(detailsFramework.IconPickFrame, nil, "$parentSearchBox", nil, 140, 20)
|
|
detailsFramework.IconPickFrame.search:SetPoint("left", detailsFramework.IconPickFrame.searchLabel, "right", 2, 0)
|
|
detailsFramework.IconPickFrame.search:SetTemplate(detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
|
|
|
detailsFramework.IconPickFrame.search:SetHook("OnTextChanged", function()
|
|
detailsFramework.IconPickFrame.searching = detailsFramework.IconPickFrame.search:GetText()
|
|
if (detailsFramework.IconPickFrame.searching == "") then
|
|
detailsFramework.IconPickFrameScroll:Show()
|
|
detailsFramework.IconPickFrame.searching = nil
|
|
detailsFramework.IconPickFrameScroll.RefreshIcons()
|
|
else
|
|
detailsFramework.IconPickFrameScroll:Hide()
|
|
FauxScrollFrame_SetOffset (detailsFramework.IconPickFrame, 1)
|
|
detailsFramework.IconPickFrame.last_filter_index = 1
|
|
detailsFramework.IconPickFrameScroll.RefreshIcons()
|
|
end
|
|
end)
|
|
|
|
--manually enter the icon path
|
|
detailsFramework.IconPickFrame.customIcon = detailsFramework:CreateLabel(detailsFramework.IconPickFrame, "Icon Path:", detailsFramework:GetTemplate("font", "ORANGE_FONT_TEMPLATE"))
|
|
detailsFramework.IconPickFrame.customIcon:SetPoint("bottomleft", detailsFramework.IconPickFrame, "bottomleft", 12, 16)
|
|
detailsFramework.IconPickFrame.customIcon.fontsize = 12
|
|
|
|
detailsFramework.IconPickFrame.customIconEntry = detailsFramework:CreateTextEntry(detailsFramework.IconPickFrame, function()end, 200, 20, "CustomIconEntry", _, _, detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
|
detailsFramework.IconPickFrame.customIconEntry:SetPoint("left", detailsFramework.IconPickFrame.customIcon, "right", 2, 0)
|
|
|
|
detailsFramework.IconPickFrame.customIconEntry:SetHook("OnTextChanged", function()
|
|
detailsFramework.IconPickFrame.preview:SetPoint("bottom", detailsFramework.IconPickFrame.customIconEntry.widget, "top", 0, 2)
|
|
detailsFramework.IconPickFrame.preview.icon:SetTexture(detailsFramework.IconPickFrame.customIconEntry:GetText())
|
|
detailsFramework.IconPickFrame.preview:Show()
|
|
end)
|
|
|
|
detailsFramework.IconPickFrame.customIconEntry:SetHook("OnEnter", function()
|
|
detailsFramework.IconPickFrame.preview:SetPoint("bottom", detailsFramework.IconPickFrame.customIconEntry.widget, "top", 0, 2)
|
|
detailsFramework.IconPickFrame.preview.icon:SetTexture(detailsFramework.IconPickFrame.customIconEntry:GetText())
|
|
detailsFramework.IconPickFrame.preview:Show()
|
|
end)
|
|
|
|
--close button
|
|
local close_button = CreateFrame("button", nil, detailsFramework.IconPickFrame, "UIPanelCloseButton", "BackdropTemplate")
|
|
close_button:SetWidth(32)
|
|
close_button:SetHeight(32)
|
|
close_button:SetPoint("TOPRIGHT", detailsFramework.IconPickFrame, "TOPRIGHT", -8, -7)
|
|
close_button:SetFrameLevel(close_button:GetFrameLevel()+2)
|
|
close_button:SetAlpha(0) --just hide, it is used below
|
|
|
|
--accept custom icon button
|
|
local accept_custom_icon = function()
|
|
local path = detailsFramework.IconPickFrame.customIconEntry:GetText()
|
|
|
|
detailsFramework:QuickDispatch(detailsFramework.IconPickFrame.callback, path, detailsFramework.IconPickFrame.param1, detailsFramework.IconPickFrame.param2)
|
|
|
|
if (detailsFramework.IconPickFrame.click_close) then
|
|
close_button:Click()
|
|
end
|
|
end
|
|
|
|
detailsFramework.IconPickFrame.customIconAccept = detailsFramework:CreateButton(detailsFramework.IconPickFrame, accept_custom_icon, 82, 20, "Accept", nil, nil, nil, nil, nil, nil, detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), detailsFramework:GetTemplate("font", "ORANGE_FONT_TEMPLATE"))
|
|
detailsFramework.IconPickFrame.customIconAccept:SetPoint("left", detailsFramework.IconPickFrame.customIconEntry, "right", 2, 0)
|
|
|
|
--fill with icons
|
|
local MACRO_ICON_FILENAMES = {}
|
|
local SPELLNAMES_CACHE = {}
|
|
|
|
detailsFramework.IconPickFrame:SetScript("OnShow", function()
|
|
MACRO_ICON_FILENAMES[1] = "INV_MISC_QUESTIONMARK"
|
|
local index = 2
|
|
|
|
for i = 1, GetNumSpellTabs() do
|
|
local tab, tabTex, offset, numSpells, _ = GetSpellTabInfo(i)
|
|
offset = offset + 1
|
|
local tabEnd = offset + numSpells
|
|
|
|
for j = offset, tabEnd - 1 do
|
|
--to get spell info by slot, you have to pass in a pet argument
|
|
local spellType, ID = GetSpellBookItemInfo(j, "player")
|
|
if (spellType ~= "FLYOUT") then
|
|
MACRO_ICON_FILENAMES [index] = GetSpellBookItemTexture(j, "player") or 0
|
|
SPELLNAMES_CACHE [index] = GetSpellInfo(ID)
|
|
index = index + 1
|
|
|
|
elseif (spellType == "FLYOUT") then
|
|
local _, _, numSlots, isKnown = GetFlyoutInfo(ID)
|
|
if (isKnown and numSlots > 0) then
|
|
for k = 1, numSlots do
|
|
local spellID, overrideSpellID, isKnown = GetFlyoutSlotInfo(ID, k)
|
|
if (isKnown) then
|
|
MACRO_ICON_FILENAMES [index] = GetSpellTexture(spellID) or 0
|
|
SPELLNAMES_CACHE [index] = GetSpellInfo(spellID)
|
|
index = index + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
GetLooseMacroItemIcons(MACRO_ICON_FILENAMES)
|
|
GetLooseMacroIcons(MACRO_ICON_FILENAMES)
|
|
GetMacroIcons(MACRO_ICON_FILENAMES)
|
|
GetMacroItemIcons(MACRO_ICON_FILENAMES)
|
|
|
|
--reset the custom icon text entry
|
|
detailsFramework.IconPickFrame.customIconEntry:SetText("")
|
|
--reset the search text entry
|
|
detailsFramework.IconPickFrame.search:SetText("")
|
|
end)
|
|
|
|
detailsFramework.IconPickFrame:SetScript("OnHide", function()
|
|
wipe(MACRO_ICON_FILENAMES)
|
|
wipe(SPELLNAMES_CACHE)
|
|
detailsFramework.IconPickFrame.preview:Hide()
|
|
collectgarbage()
|
|
end)
|
|
|
|
detailsFramework.IconPickFrame.buttons = {}
|
|
|
|
local onClickFunction = function(self)
|
|
|
|
detailsFramework:QuickDispatch(detailsFramework.IconPickFrame.callback, self.icon:GetTexture(), detailsFramework.IconPickFrame.param1, detailsFramework.IconPickFrame.param2)
|
|
|
|
if (detailsFramework.IconPickFrame.click_close) then
|
|
close_button:Click()
|
|
end
|
|
end
|
|
|
|
local onEnter = function(self)
|
|
detailsFramework.IconPickFrame.preview:SetPoint("bottom", self, "top", 0, 2)
|
|
detailsFramework.IconPickFrame.preview.icon:SetTexture(self.icon:GetTexture())
|
|
detailsFramework.IconPickFrame.preview:Show()
|
|
self.icon:SetBlendMode("ADD")
|
|
end
|
|
local onLeave = function(self)
|
|
detailsFramework.IconPickFrame.preview:Hide()
|
|
self.icon:SetBlendMode("BLEND")
|
|
end
|
|
|
|
local backdrop = {bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tile = true, tileSize = 16,
|
|
insets = {left = 0, right = 0, top = 0, bottom = 0}, edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1}
|
|
|
|
for _, button in ipairs(detailsFramework.IconPickFrame.buttons) do
|
|
button:SetBackdropBorderColor(0, 0, 0, 1)
|
|
end
|
|
|
|
local width = 412
|
|
local height = 248
|
|
local linesAmount = 6
|
|
local lineHeight = 40
|
|
|
|
local updateIconScroll = function(self, data, offset, totalLines)
|
|
for i = 1, totalLines do
|
|
local index = i + offset
|
|
local iconsInThisLine = data[index]
|
|
if (iconsInThisLine) then
|
|
local line = self:GetLine(i)
|
|
for o = 1, #iconsInThisLine do
|
|
local _, _, texture = GetSpellInfo(iconsInThisLine[o])
|
|
if (texture) then
|
|
line.buttons[o].icon:SetTexture(texture)
|
|
line.buttons[o].texture = texture
|
|
else
|
|
line.buttons[o].icon:SetTexture(iconsInThisLine[o])
|
|
line.buttons[o].texture = iconsInThisLine[o]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local lower = string.lower
|
|
|
|
local scroll = detailsFramework:CreateScrollBox(detailsFramework.IconPickFrame, "DetailsFrameworkIconPickFrameScroll", updateIconScroll, {}, width, height, linesAmount, lineHeight)
|
|
detailsFramework:ReskinSlider(scroll)
|
|
scroll:SetPoint("topleft", detailsFramework.IconPickFrame, "topleft", 2, -58)
|
|
|
|
function scroll.RefreshIcons()
|
|
--build icon list
|
|
local iconList = {}
|
|
local numMacroIcons = #MACRO_ICON_FILENAMES
|
|
|
|
local filter
|
|
if (detailsFramework.IconPickFrame.searching) then
|
|
filter = lower(detailsFramework.IconPickFrame.searching)
|
|
end
|
|
|
|
if (filter and filter ~= "") then
|
|
local index
|
|
local currentTable
|
|
for i = 1, #SPELLNAMES_CACHE do
|
|
if (SPELLNAMES_CACHE[i] and SPELLNAMES_CACHE[i]:lower():find(filter)) then
|
|
if (not index) then
|
|
index = 1
|
|
local t = {}
|
|
iconList[#iconList+1] = t
|
|
currentTable = t
|
|
end
|
|
|
|
currentTable[index] = SPELLNAMES_CACHE[i]
|
|
|
|
index = index + 1
|
|
if (index == 11) then
|
|
index = nil
|
|
end
|
|
end
|
|
|
|
end
|
|
else
|
|
for i = 1, #SPELLNAMES_CACHE, 10 do
|
|
local t = {}
|
|
iconList[#iconList+1] = t
|
|
for o = i, i+9 do
|
|
if (SPELLNAMES_CACHE[o]) then
|
|
t[#t+1] = SPELLNAMES_CACHE[o]
|
|
end
|
|
end
|
|
end
|
|
|
|
for i = 1, #MACRO_ICON_FILENAMES, 10 do
|
|
local t = {}
|
|
iconList[#iconList+1] = t
|
|
for o = i, i+9 do
|
|
if (MACRO_ICON_FILENAMES[o]) then
|
|
t[#t+1] = MACRO_ICON_FILENAMES[o]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--set data and refresh
|
|
scroll:SetData(iconList)
|
|
scroll:Refresh()
|
|
end
|
|
|
|
--create the lines and button of the scroll box
|
|
for i = 1, linesAmount do
|
|
scroll:CreateLine(function(self, index)
|
|
local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate")
|
|
line:SetPoint("topleft", self, "topleft", 1, -((index-1)*(lineHeight+1)) - 1)
|
|
line:SetSize(width - 2, lineHeight)
|
|
line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
|
line:SetBackdropColor(.2, .2, .2, .5)
|
|
line.buttons = {}
|
|
|
|
local lastButton
|
|
|
|
for o = 1, 10 do
|
|
local button = CreateFrame("button", "$parentIcon" .. o, line)
|
|
if (not lastButton) then
|
|
button:SetPoint("left", line, "left", 0, 0)
|
|
else
|
|
button:SetPoint("left", lastButton, "right", 1, 0)
|
|
end
|
|
button:SetSize(lineHeight, lineHeight)
|
|
button.icon = button:CreateTexture("$parentIcon", "overlay")
|
|
button.icon:SetAllPoints()
|
|
button.icon:SetTexCoord(.1, .9, .1, .9)
|
|
line.buttons[o] = button
|
|
|
|
button:SetScript("OnEnter", onEnter)
|
|
button:SetScript("OnLeave", onLeave)
|
|
button:SetScript("OnClick", onClickFunction)
|
|
|
|
lastButton = button
|
|
end
|
|
|
|
return line
|
|
end)
|
|
end
|
|
|
|
detailsFramework.IconPickFrameScroll = scroll
|
|
detailsFramework.IconPickFrame:Hide()
|
|
end
|
|
|
|
detailsFramework.IconPickFrame.param1, detailsFramework.IconPickFrame.param2 = param1, param2
|
|
detailsFramework.IconPickFrame:Show()
|
|
detailsFramework.IconPickFrame.callback = callback or detailsFramework.IconPickFrame.emptyFunction
|
|
detailsFramework.IconPickFrame.click_close = close_when_select
|
|
detailsFramework.IconPickFrameScroll.RefreshIcons()
|
|
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
function detailsFramework:ShowPanicWarning (text)
|
|
if (not detailsFramework.PanicWarningWindow) then
|
|
detailsFramework.PanicWarningWindow = CreateFrame("frame", "DetailsFrameworkPanicWarningWindow", UIParent, "BackdropTemplate")
|
|
detailsFramework.PanicWarningWindow:SetHeight(80)
|
|
detailsFramework.PanicWarningWindow:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
|
detailsFramework.PanicWarningWindow:SetBackdropColor(1, 0, 0, 0.2)
|
|
detailsFramework.PanicWarningWindow:SetPoint("topleft", UIParent, "topleft", 0, -250)
|
|
detailsFramework.PanicWarningWindow:SetPoint("topright", UIParent, "topright", 0, -250)
|
|
|
|
detailsFramework.PanicWarningWindow.text = detailsFramework.PanicWarningWindow:CreateFontString(nil, "overlay", "GameFontNormal")
|
|
detailsFramework.PanicWarningWindow.text:SetPoint("center", detailsFramework.PanicWarningWindow, "center")
|
|
detailsFramework.PanicWarningWindow.text:SetTextColor(1, 0.6, 0)
|
|
end
|
|
|
|
detailsFramework.PanicWarningWindow.text:SetText(text)
|
|
detailsFramework.PanicWarningWindow:Show()
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
local simple_panel_mouse_down = function(self, button)
|
|
if (button == "RightButton") then
|
|
if (self.IsMoving) then
|
|
self.IsMoving = false
|
|
self:StopMovingOrSizing()
|
|
if (self.db and self.db.position) then
|
|
detailsFramework:SavePositionOnScreen (self)
|
|
end
|
|
end
|
|
if (not self.DontRightClickClose) then
|
|
self:Hide()
|
|
end
|
|
return
|
|
end
|
|
if (not self.IsMoving and not self.IsLocked) then
|
|
self.IsMoving = true
|
|
self:StartMoving()
|
|
end
|
|
end
|
|
local simple_panel_mouse_up = function(self, button)
|
|
if (self.IsMoving) then
|
|
self.IsMoving = false
|
|
self:StopMovingOrSizing()
|
|
if (self.db and self.db.position) then
|
|
detailsFramework:SavePositionOnScreen (self)
|
|
end
|
|
end
|
|
end
|
|
local simple_panel_settitle = function(self, title)
|
|
self.Title:SetText(title)
|
|
end
|
|
|
|
local simple_panel_close_click = function(self)
|
|
self:GetParent():GetParent():Hide()
|
|
end
|
|
|
|
local SimplePanel_frame_backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}
|
|
local SimplePanel_frame_backdrop_color = {0, 0, 0, 0.9}
|
|
local SimplePanel_frame_backdrop_border_color = {0, 0, 0, 1}
|
|
|
|
--with_label was making the frame stay in place while its parent moves
|
|
--the slider was anchoring to with_label and here here were anchoring the slider again
|
|
---@class df_scalebar : slider
|
|
---@field thumb texture
|
|
function detailsFramework:CreateScaleBar(frame, config) --~scale
|
|
---@type df_scalebar
|
|
local scaleBar, text = detailsFramework:CreateSlider(frame, 120, 14, 0.6, 1.6, 0.1, config.scale, true, "ScaleBar", nil, "Scale:", detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE"), detailsFramework:GetTemplate("font", "ORANGE_FONT_TEMPLATE"))
|
|
scaleBar.thumb:SetWidth(24)
|
|
scaleBar:SetValueStep(0.1)
|
|
scaleBar:SetObeyStepOnDrag(true)
|
|
scaleBar.mouseDown = false
|
|
rawset(scaleBar, "lockdown", true)
|
|
|
|
--create a custom editbox to enter the scale from text
|
|
local editbox = CreateFrame("editbox", nil, scaleBar.widget, "BackdropTemplate")
|
|
editbox:SetSize(40, 20)
|
|
editbox:SetJustifyH("center")
|
|
editbox:SetBackdrop({bgFile = [[Interface\ACHIEVEMENTFRAME\UI-GuildAchievement-Parchment-Horizontal-Desaturated]],
|
|
edgeFile = [[Interface\Buttons\WHITE8X8]],
|
|
tile = true, edgeSize = 1, tileSize = 64})
|
|
editbox:SetFontObject("GameFontHighlightSmall")
|
|
editbox:SetBackdropColor(0, 0, 0, 1)
|
|
|
|
editbox:SetScript("OnEditFocusGained", function()
|
|
end)
|
|
|
|
editbox:SetScript("OnEnterPressed", function()
|
|
editbox:ClearFocus()
|
|
editbox:Hide()
|
|
local text = editbox:GetText()
|
|
local newScale = detailsFramework.TextToFloor(text)
|
|
|
|
if (newScale) then
|
|
config.scale = newScale
|
|
scaleBar:SetValue(newScale)
|
|
frame:SetScale(newScale)
|
|
editbox.defaultValue = newScale
|
|
end
|
|
end)
|
|
|
|
editbox:SetScript("OnEscapePressed", function()
|
|
editbox:ClearFocus()
|
|
editbox:Hide()
|
|
editbox:SetText(editbox.defaultValue)
|
|
end)
|
|
|
|
scaleBar:SetScript("OnMouseDown", function(_, mouseButton)
|
|
if (mouseButton == "RightButton") then
|
|
editbox:Show()
|
|
editbox:SetAllPoints()
|
|
editbox:SetText(config.scale)
|
|
editbox:SetFocus(true)
|
|
editbox.defaultValue = config.scale
|
|
|
|
elseif (mouseButton == "LeftButton") then
|
|
scaleBar.mouseDown = true
|
|
end
|
|
end)
|
|
|
|
scaleBar:SetScript("OnMouseUp", function(_, mouseButton)
|
|
if (mouseButton == "LeftButton") then
|
|
scaleBar.mouseDown = false
|
|
frame:SetScale(config.scale)
|
|
editbox.defaultValue = config.scale
|
|
end
|
|
end)
|
|
|
|
text:SetPoint("topleft", frame, "topleft", 12, -7)
|
|
scaleBar:SetFrameLevel(detailsFramework.FRAMELEVEL_OVERLAY)
|
|
scaleBar.OnValueChanged = function(_, _, value)
|
|
if (scaleBar.mouseDown) then
|
|
config.scale = value
|
|
end
|
|
end
|
|
|
|
scaleBar:SetAlpha(0.70)
|
|
editbox.defaultValue = config.scale
|
|
editbox:SetFocus(false)
|
|
editbox:SetAutoFocus(false)
|
|
editbox:ClearFocus()
|
|
|
|
C_Timer.After(1, function()
|
|
editbox:SetFocus(false)
|
|
editbox:SetAutoFocus(false)
|
|
editbox:ClearFocus()
|
|
end)
|
|
|
|
return scaleBar
|
|
end
|
|
|
|
local no_options = {}
|
|
|
|
---create a simple panel with a title bar, a close button and a background
|
|
---already has onmousedown and onmouseup scripts to make it movable
|
|
---the panelOptions table can be used to set some options:
|
|
---NoScripts = false, --if true, won't set OnMouseDown and OnMouseUp (won't be movable)
|
|
---NoTUISpecialFrame = false, --if true, won't add the frame to 'UISpecialFrames'
|
|
---DontRightClickClose = false, --if true, won't make the frame close when clicked with the right mouse button
|
|
---UseScaleBar = false, --if true, will create a scale bar in the top left corner (require a table on 'db' to save the scale)
|
|
---UseStatusBar = false, --if true, creates a status bar at the bottom of the frame (frame.StatusBar)
|
|
---NoCloseButton = false, --if true, won't show the close button
|
|
---NoTitleBar = false, --if true, don't create the title bar
|
|
---RoundedCorners = false, --use rounded corners if true
|
|
---@class simplepanel
|
|
---@field TitleBar frame
|
|
---@field Title fontstring
|
|
---@field Close button
|
|
---@field SetTitle fun(self: simplepanel, title: string)
|
|
---@param parent frame the parent frame
|
|
---@param width number? the width of the panel
|
|
---@param height number? the height of the panel
|
|
---@param title string? a string to show in the title bar
|
|
---@param frameName string? the name of the frame
|
|
---@param panelOptions table? a table with options described above
|
|
---@param savedVariableTable table? a table to save the scale of the panel
|
|
---@return frame
|
|
function detailsFramework:CreateSimplePanel(parent, width, height, title, frameName, panelOptions, savedVariableTable)
|
|
--create a saved variable table if the savedVariableTable has been not passed within the function call
|
|
if (savedVariableTable and frameName and not savedVariableTable[frameName]) then
|
|
savedVariableTable[frameName] = {
|
|
scale = 1
|
|
}
|
|
end
|
|
|
|
--create a frame name if the frameName has been not passed within the function call
|
|
if (not frameName) then
|
|
frameName = "DetailsFrameworkSimplePanel" .. detailsFramework.SimplePanelCounter
|
|
detailsFramework.SimplePanelCounter = detailsFramework.SimplePanelCounter + 1
|
|
end
|
|
|
|
--default parent is UIParent
|
|
if (not parent) then
|
|
parent = _G["UIParent"]
|
|
end
|
|
|
|
--default options
|
|
panelOptions = panelOptions or no_options
|
|
|
|
--create the frame
|
|
local simplePanel = CreateFrame("frame", frameName, _G["UIParent"],"BackdropTemplate")
|
|
simplePanel:SetSize(width or 400, height or 250)
|
|
simplePanel:SetPoint("center", _G["UIParent"], "center", 0, 0)
|
|
simplePanel:SetFrameStrata("FULLSCREEN")
|
|
simplePanel:EnableMouse()
|
|
simplePanel:SetMovable(true)
|
|
|
|
--set the backdrop
|
|
if (panelOptions.RoundedCorners) then
|
|
local tRoundedCornerPreset = {
|
|
roundness = 6,
|
|
color = {.1, .1, .1, 0.98},
|
|
border_color = {.05, .05, .05, 0.834},
|
|
use_titlebar = true,
|
|
}
|
|
detailsFramework:AddRoundedCornersToFrame(simplePanel, tRoundedCornerPreset)
|
|
else
|
|
simplePanel:SetBackdrop(SimplePanel_frame_backdrop)
|
|
simplePanel:SetBackdropColor(unpack(SimplePanel_frame_backdrop_color))
|
|
simplePanel:SetBackdropBorderColor(unpack(SimplePanel_frame_backdrop_border_color))
|
|
end
|
|
|
|
simplePanel.DontRightClickClose = panelOptions.DontRightClickClose
|
|
|
|
if (not panelOptions.NoTUISpecialFrame) then
|
|
table.insert(UISpecialFrames, frameName)
|
|
end
|
|
|
|
if (panelOptions.UseStatusBar and not panelOptions.RoundedCorners) then
|
|
local statusBar = detailsFramework:CreateStatusBar(simplePanel)
|
|
simplePanel.StatusBar = statusBar
|
|
end
|
|
|
|
local titleBar = CreateFrame("frame", frameName .. "TitleBar", simplePanel, "BackdropTemplate")
|
|
|
|
if (panelOptions.RoundedCorners) then
|
|
simplePanel.TitleBar:SetColor(.2, .2, .2, 0.4)
|
|
simplePanel.TitleBar:SetBorderCornerColor(0, 0, 0, 0)
|
|
|
|
else
|
|
simplePanel.TitleBar = titleBar
|
|
titleBar:SetPoint("topleft", simplePanel, "topleft", 2, -3)
|
|
titleBar:SetPoint("topright", simplePanel, "topright", -2, -3)
|
|
titleBar:SetHeight(20)
|
|
titleBar:SetBackdrop(SimplePanel_frame_backdrop)
|
|
titleBar:SetBackdropColor(.2, .2, .2, 1)
|
|
titleBar:SetBackdropBorderColor(0, 0, 0, 1)
|
|
simplePanel.TitleBar = titleBar
|
|
end
|
|
|
|
local close = CreateFrame("button", frameName and frameName .. "CloseButton", titleBar)
|
|
close:SetFrameLevel(detailsFramework.FRAMELEVEL_OVERLAY)
|
|
close:SetSize(16, 16)
|
|
|
|
close:SetNormalTexture([[Interface\GLUES\LOGIN\Glues-CheckBox-Check]])
|
|
close:SetHighlightTexture([[Interface\GLUES\LOGIN\Glues-CheckBox-Check]])
|
|
close:SetPushedTexture([[Interface\GLUES\LOGIN\Glues-CheckBox-Check]])
|
|
close:GetNormalTexture():SetDesaturated(true)
|
|
close:GetHighlightTexture():SetDesaturated(true)
|
|
close:GetPushedTexture():SetDesaturated(true)
|
|
|
|
close:SetAlpha(0.7)
|
|
close:SetScript("OnClick", simple_panel_close_click)
|
|
simplePanel.Close = close
|
|
simplePanel.closeButton = close
|
|
|
|
local titleText = titleBar:CreateFontString(frameName and frameName .. "Title", "overlay", "GameFontNormal")
|
|
titleText:SetTextColor(.8, .8, .8, 1)
|
|
titleText:SetText(title or "")
|
|
simplePanel.Title = titleText
|
|
|
|
if (panelOptions.UseScaleBar and savedVariableTable and savedVariableTable[frameName]) then
|
|
detailsFramework:CreateScaleBar(simplePanel, savedVariableTable[frameName])
|
|
simplePanel:SetScale(savedVariableTable[frameName].scale)
|
|
end
|
|
|
|
simplePanel.Title:SetPoint("center", titleBar, "center")
|
|
simplePanel.Close:SetPoint("right", titleBar, "right", -2, 0)
|
|
|
|
if (panelOptions.NoCloseButton or panelOptions.RoundedCorners) then
|
|
simplePanel.Close:Hide()
|
|
end
|
|
|
|
if (panelOptions.NoTitleBar) then
|
|
simplePanel.TitleBar:Hide()
|
|
end
|
|
|
|
if (not panelOptions.NoScripts) then
|
|
simplePanel:SetScript("OnMouseDown", simple_panel_mouse_down)
|
|
simplePanel:SetScript("OnMouseUp", simple_panel_mouse_up)
|
|
end
|
|
|
|
simplePanel.SetTitle = simple_panel_settitle
|
|
|
|
return simplePanel
|
|
end
|
|
|
|
local Panel1PxBackdrop = {bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 64,
|
|
edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, insets = {left = 2, right = 2, top = 3, bottom = 3}}
|
|
|
|
local Panel1PxOnClickClose = function(self)
|
|
self:GetParent():Hide()
|
|
end
|
|
local Panel1PxOnToggleLock = function(self)
|
|
if (self.IsLocked) then
|
|
self.IsLocked = false
|
|
self:SetMovable(true)
|
|
self:EnableMouse(true)
|
|
self.Lock:GetNormalTexture():SetTexCoord(16/64, 32/64, 0, 1)
|
|
self.Lock:GetHighlightTexture():SetTexCoord(16/32, 32/64, 0, 1)
|
|
self.Lock:GetPushedTexture():SetTexCoord(16/64, 32/64, 0, 1)
|
|
if (self.OnUnlock) then
|
|
self:OnUnlock()
|
|
end
|
|
if (self.db) then
|
|
self.db.IsLocked = self.IsLocked
|
|
end
|
|
else
|
|
self.IsLocked = true
|
|
self:SetMovable(false)
|
|
self:EnableMouse(false)
|
|
self.Lock:GetNormalTexture():SetTexCoord(0/64, 16/64, 0, 1)
|
|
self.Lock:GetHighlightTexture():SetTexCoord(0/64, 16/64, 0, 1)
|
|
self.Lock:GetPushedTexture():SetTexCoord(0/64, 16/64, 0, 1)
|
|
if (self.OnLock) then
|
|
self:OnLock()
|
|
end
|
|
if (self.db) then
|
|
self.db.IsLocked = self.IsLocked
|
|
end
|
|
end
|
|
end
|
|
local Panel1PxOnClickLock = function(self)
|
|
local f = self:GetParent()
|
|
Panel1PxOnToggleLock (f)
|
|
end
|
|
local Panel1PxSetTitle = function(self, text)
|
|
self.Title:SetText(text or "")
|
|
end
|
|
|
|
local Panel1PxSetLocked= function(self, lock_state)
|
|
if (type(lock_state) ~= "boolean") then
|
|
return
|
|
end
|
|
if (lock_state) then
|
|
-- lock it
|
|
self.IsLocked = false
|
|
Panel1PxOnClickLock (self.Lock)
|
|
else
|
|
-- unlockit
|
|
self.IsLocked = true
|
|
Panel1PxOnClickLock (self.Lock)
|
|
end
|
|
end
|
|
|
|
local Panel1PxReadConfig = function(self)
|
|
local db = self.db
|
|
if (db) then
|
|
db.IsLocked = db.IsLocked or false
|
|
self.IsLocked = db.IsLocked
|
|
db.position = db.position or {x = 0, y = 0}
|
|
db.position.x = db.position.x or 0
|
|
db.position.y = db.position.y or 0
|
|
detailsFramework:RestoreFramePosition (self)
|
|
end
|
|
end
|
|
|
|
function detailsFramework:SavePositionOnScreen (frame)
|
|
if (frame.db and frame.db.position) then
|
|
local x, y = detailsFramework:GetPositionOnScreen (frame)
|
|
--print("saving...", x, y, frame:GetName())
|
|
if (x and y) then
|
|
frame.db.position.x, frame.db.position.y = x, y
|
|
end
|
|
end
|
|
end
|
|
|
|
function detailsFramework:GetPositionOnScreen (frame)
|
|
local xOfs, yOfs = frame:GetCenter()
|
|
if (not xOfs) then
|
|
return
|
|
end
|
|
local scale = frame:GetEffectiveScale()
|
|
local UIscale = UIParent:GetScale()
|
|
xOfs = xOfs*scale - GetScreenWidth()*UIscale/2
|
|
yOfs = yOfs*scale - GetScreenHeight()*UIscale/2
|
|
return xOfs/UIscale, yOfs/UIscale
|
|
end
|
|
|
|
function detailsFramework:RestoreFramePosition (frame)
|
|
if (frame.db and frame.db.position) then
|
|
local scale, UIscale = frame:GetEffectiveScale(), UIParent:GetScale()
|
|
frame:ClearAllPoints()
|
|
frame.db.position.x = frame.db.position.x or 0
|
|
frame.db.position.y = frame.db.position.y or 0
|
|
frame:SetPoint("center", UIParent, "center", frame.db.position.x * UIscale / scale, frame.db.position.y * UIscale / scale)
|
|
end
|
|
end
|
|
|
|
local Panel1PxSavePosition= function(self)
|
|
detailsFramework:SavePositionOnScreen (self)
|
|
end
|
|
|
|
local Panel1PxHasPosition = function(self)
|
|
local db = self.db
|
|
if (db) then
|
|
if (db.position and db.position.x and (db.position.x ~= 0 or db.position.y ~= 0)) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
function detailsFramework:Create1PxPanel(parent, width, height, title, name, config, titleAnchor, noSpecialFrame)
|
|
local newFrame = CreateFrame("frame", name, parent or UIParent, "BackdropTemplate")
|
|
newFrame:SetSize(width or 100, height or 75)
|
|
newFrame:SetPoint("center", UIParent, "center", 0, 0)
|
|
|
|
if (name and not noSpecialFrame) then
|
|
table.insert(UISpecialFrames, name)
|
|
end
|
|
|
|
newFrame:SetScript("OnMouseDown", simple_panel_mouse_down)
|
|
newFrame:SetScript("OnMouseUp", simple_panel_mouse_up)
|
|
|
|
newFrame:SetBackdrop(Panel1PxBackdrop)
|
|
newFrame:SetBackdropColor(0, 0, 0, 0.5)
|
|
|
|
newFrame.IsLocked = (config and config.IsLocked ~= nil and config.IsLocked) or false
|
|
newFrame:SetMovable(true)
|
|
newFrame:EnableMouse(true)
|
|
newFrame:SetUserPlaced (true)
|
|
|
|
newFrame.db = config
|
|
Panel1PxReadConfig(newFrame)
|
|
|
|
local closeButton = CreateFrame("button", name and name .. "CloseButton", newFrame, "BackdropTemplate")
|
|
closeButton:SetSize(16, 16)
|
|
closeButton:SetNormalTexture([[Interface\GLUES\LOGIN\Glues-CheckBox-Check]])
|
|
closeButton:SetHighlightTexture([[Interface\GLUES\LOGIN\Glues-CheckBox-Check]])
|
|
closeButton:SetPushedTexture([[Interface\GLUES\LOGIN\Glues-CheckBox-Check]])
|
|
closeButton:GetNormalTexture():SetDesaturated(true)
|
|
closeButton:GetHighlightTexture():SetDesaturated(true)
|
|
closeButton:GetPushedTexture():SetDesaturated(true)
|
|
closeButton:SetAlpha(0.7)
|
|
|
|
local lockButton = CreateFrame("button", name and name .. "LockButton", newFrame, "BackdropTemplate")
|
|
lockButton:SetSize(16, 16)
|
|
lockButton:SetNormalTexture([[Interface\GLUES\CharacterSelect\Glues-AddOn-Icons]])
|
|
lockButton:SetHighlightTexture([[Interface\GLUES\CharacterSelect\Glues-AddOn-Icons]])
|
|
lockButton:SetPushedTexture([[Interface\GLUES\CharacterSelect\Glues-AddOn-Icons]])
|
|
lockButton:GetNormalTexture():SetDesaturated(true)
|
|
lockButton:GetHighlightTexture():SetDesaturated(true)
|
|
lockButton:GetPushedTexture():SetDesaturated(true)
|
|
lockButton:SetAlpha(0.7)
|
|
|
|
closeButton:SetPoint("topright", newFrame, "topright", -3, -3)
|
|
lockButton:SetPoint("right", closeButton, "left", 3, 0)
|
|
|
|
closeButton:SetScript("OnClick", Panel1PxOnClickClose)
|
|
lockButton:SetScript("OnClick", Panel1PxOnClickLock)
|
|
|
|
local titleString = newFrame:CreateFontString(name and name .. "Title", "overlay", "GameFontNormal")
|
|
titleString:SetPoint("topleft", newFrame, "topleft", 5, -5)
|
|
|
|
detailsFramework.Language.SetTextIfLocTableOrDefault(titleString, title or "")
|
|
|
|
if (titleAnchor) then
|
|
if (titleAnchor == "top") then
|
|
titleString:ClearAllPoints()
|
|
titleString:SetPoint("bottomleft", newFrame, "topleft", 0, 0)
|
|
|
|
closeButton:ClearAllPoints()
|
|
closeButton:SetPoint("bottomright", newFrame, "topright", 0, 0)
|
|
end
|
|
newFrame.title_anchor = titleAnchor
|
|
end
|
|
|
|
newFrame.SetTitle = Panel1PxSetTitle
|
|
newFrame.Title = titleString
|
|
newFrame.Lock = lockButton
|
|
newFrame.Close = closeButton
|
|
newFrame.HasPosition = Panel1PxHasPosition
|
|
newFrame.SavePosition = Panel1PxSavePosition
|
|
|
|
newFrame.IsLocked = not newFrame.IsLocked
|
|
newFrame.SetLocked = Panel1PxSetLocked
|
|
Panel1PxOnToggleLock(newFrame)
|
|
|
|
return newFrame
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- ~prompt
|
|
function detailsFramework:HidePromptPanel(promptName)
|
|
if (detailsFramework.promtp_panel) then
|
|
if (promptName) then
|
|
if (detailsFramework.promtp_panel.promptName == promptName) then
|
|
detailsFramework.promtp_panel:Hide()
|
|
detailsFramework.promtp_panel.promptName = nil
|
|
end
|
|
else
|
|
detailsFramework.promtp_panel:Hide()
|
|
detailsFramework.promtp_panel.promptName = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
---show a prompt to the player with a question (message) and two buttons "yes" and "no"
|
|
---@param message string the question to show to the player
|
|
---@param trueCallback function if the player clicks on "yes"
|
|
---@param falseCallback function if the player clicks on "no"
|
|
---@param dontOverride boolean|nil if true, won't show another prompt if theres already a shown prompt
|
|
---@param width number|nil width of the prompt frame, if ommited, will use the default width 400
|
|
---@param promptName string|nil set a name to the prompt, used on HidePromptPanel(promptName)
|
|
function detailsFramework:ShowPromptPanel(message, trueCallback, falseCallback, dontOverride, width, promptName)
|
|
if (not DetailsFrameworkPromptSimple) then
|
|
local promptFrame = CreateFrame("frame", "DetailsFrameworkPromptSimple", UIParent, "BackdropTemplate")
|
|
promptFrame:SetSize(400, 80)
|
|
promptFrame:SetFrameStrata("DIALOG")
|
|
promptFrame:SetPoint("center", UIParent, "center", 0, 300)
|
|
detailsFramework:ApplyStandardBackdrop(promptFrame)
|
|
table.insert(UISpecialFrames, "DetailsFrameworkPromptSimple")
|
|
|
|
detailsFramework:CreateTitleBar(promptFrame, "Prompt!")
|
|
detailsFramework:ApplyStandardBackdrop(promptFrame)
|
|
|
|
local prompt = promptFrame:CreateFontString(nil, "overlay", "GameFontNormal")
|
|
prompt:SetPoint("top", promptFrame, "top", 0, -28)
|
|
prompt:SetJustifyH("center")
|
|
promptFrame.prompt = prompt
|
|
|
|
local button_text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")
|
|
local options_dropdown_template = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")
|
|
|
|
local buttonTrue = detailsFramework:CreateButton(promptFrame, nil, 60, 20, "Yes", nil, nil, nil, nil, nil, nil, options_dropdown_template)
|
|
buttonTrue:SetPoint("bottomright", promptFrame, "bottomright", -5, 5)
|
|
promptFrame.button_true = buttonTrue
|
|
|
|
local buttonFalse = detailsFramework:CreateButton(promptFrame, nil, 60, 20, "No", nil, nil, nil, nil, nil, nil, options_dropdown_template)
|
|
buttonFalse:SetPoint("bottomleft", promptFrame, "bottomleft", 5, 5)
|
|
promptFrame.button_false = buttonFalse
|
|
|
|
buttonTrue:SetClickFunction(function()
|
|
local my_func = buttonTrue.true_function
|
|
if (my_func) then
|
|
local okey, errormessage = pcall(my_func, true)
|
|
if (not okey) then
|
|
print("error:", errormessage)
|
|
end
|
|
promptFrame:Hide()
|
|
end
|
|
end)
|
|
|
|
buttonFalse:SetClickFunction(function()
|
|
local my_func = buttonFalse.false_function
|
|
if (my_func) then
|
|
local okey, errormessage = pcall(my_func, true)
|
|
if (not okey) then
|
|
print("error:", errormessage)
|
|
end
|
|
promptFrame:Hide()
|
|
end
|
|
end)
|
|
|
|
promptFrame.ShowAnimation = detailsFramework:CreateAnimationHub(promptFrame, function()
|
|
promptFrame:SetBackdropBorderColor(0, 0, 0, 0)
|
|
promptFrame.TitleBar:SetBackdropBorderColor(0, 0, 0, 0)
|
|
end,
|
|
function()
|
|
promptFrame:SetBackdropBorderColor(0, 0, 0, 1)
|
|
promptFrame.TitleBar:SetBackdropBorderColor(0, 0, 0, 1)
|
|
end)
|
|
|
|
detailsFramework:CreateAnimation(promptFrame.ShowAnimation, "scale", 1, .075, .2, .2, 1.1, 1.1, "center", 0, 0)
|
|
detailsFramework:CreateAnimation(promptFrame.ShowAnimation, "scale", 2, .075, 1, 1, .90, .90, "center", 0, 0)
|
|
|
|
promptFrame.FlashTexture = promptFrame:CreateTexture(nil, "overlay")
|
|
promptFrame.FlashTexture:SetColorTexture(1, 1, 1, 1)
|
|
promptFrame.FlashTexture:SetAllPoints()
|
|
|
|
promptFrame.FlashAnimation = detailsFramework:CreateAnimationHub(promptFrame.FlashTexture, function() promptFrame.FlashTexture:Show() end, function() promptFrame.FlashTexture:Hide() end)
|
|
detailsFramework:CreateAnimation(promptFrame.FlashAnimation, "alpha", 1, .075, 0, .25)
|
|
detailsFramework:CreateAnimation(promptFrame.FlashAnimation, "alpha", 2, .075, .35, 0)
|
|
|
|
promptFrame:Hide()
|
|
detailsFramework.promtp_panel = promptFrame
|
|
end
|
|
|
|
assert(type(trueCallback) == "function" and type(falseCallback) == "function", "ShowPromptPanel expects two functions.")
|
|
|
|
if (dontOverride) then
|
|
if (detailsFramework.promtp_panel:IsShown()) then
|
|
return
|
|
end
|
|
end
|
|
|
|
if (width) then
|
|
detailsFramework.promtp_panel:SetWidth(width)
|
|
else
|
|
detailsFramework.promtp_panel:SetWidth(400)
|
|
end
|
|
|
|
detailsFramework.promtp_panel.promptName = promptName
|
|
|
|
detailsFramework.promtp_panel.prompt:SetText(message)
|
|
detailsFramework.promtp_panel.button_true.true_function = trueCallback
|
|
detailsFramework.promtp_panel.button_false.false_function = falseCallback
|
|
|
|
detailsFramework.promtp_panel:Show()
|
|
|
|
detailsFramework.promtp_panel.ShowAnimation:Play()
|
|
detailsFramework.promtp_panel.FlashAnimation:Play()
|
|
end
|
|
|
|
|
|
function detailsFramework:ShowTextPromptPanel(message, callback)
|
|
if (not detailsFramework.text_prompt_panel) then
|
|
local promptFrame = CreateFrame("frame", "DetailsFrameworkPrompt", UIParent, "BackdropTemplate")
|
|
promptFrame:SetSize(400, 120)
|
|
promptFrame:SetFrameStrata("FULLSCREEN")
|
|
promptFrame:SetPoint("center", UIParent, "center", 0, 100)
|
|
promptFrame:EnableMouse(true)
|
|
promptFrame:SetMovable(true)
|
|
promptFrame:RegisterForDrag ("LeftButton")
|
|
promptFrame:SetScript("OnDragStart", function() promptFrame:StartMoving() end)
|
|
promptFrame:SetScript("OnDragStop", function() promptFrame:StopMovingOrSizing() end)
|
|
promptFrame:SetScript("OnMouseDown", function(self, button) if (button == "RightButton") then promptFrame.EntryBox:ClearFocus() promptFrame:Hide() end end)
|
|
table.insert(UISpecialFrames, "DetailsFrameworkPrompt")
|
|
|
|
detailsFramework:CreateTitleBar (promptFrame, "Prompt!")
|
|
detailsFramework:ApplyStandardBackdrop(promptFrame)
|
|
|
|
local prompt = promptFrame:CreateFontString(nil, "overlay", "GameFontNormal")
|
|
prompt:SetPoint("top", promptFrame, "top", 0, -25)
|
|
prompt:SetJustifyH("center")
|
|
prompt:SetSize(360, 36)
|
|
promptFrame.prompt = prompt
|
|
|
|
local button_text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")
|
|
local options_dropdown_template = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")
|
|
|
|
local textbox = detailsFramework:CreateTextEntry(promptFrame, function()end, 380, 20, "textbox", nil, nil, options_dropdown_template)
|
|
textbox:SetPoint("topleft", promptFrame, "topleft", 10, -60)
|
|
promptFrame.EntryBox = textbox
|
|
|
|
local buttonTrue = detailsFramework:CreateButton(promptFrame, nil, 60, 20, "Okey", nil, nil, nil, nil, nil, nil, options_dropdown_template)
|
|
buttonTrue:SetPoint("bottomright", promptFrame, "bottomright", -10, 5)
|
|
promptFrame.button_true = buttonTrue
|
|
|
|
local buttonFalse = detailsFramework:CreateButton(promptFrame, function() promptFrame.textbox:ClearFocus() promptFrame:Hide() end, 60, 20, "Cancel", nil, nil, nil, nil, nil, nil, options_dropdown_template)
|
|
buttonFalse:SetPoint("bottomleft", promptFrame, "bottomleft", 10, 5)
|
|
promptFrame.button_false = buttonFalse
|
|
|
|
local executeCallback = function()
|
|
local my_func = buttonTrue.true_function
|
|
if (my_func) then
|
|
local okey, errormessage = pcall(my_func, textbox:GetText())
|
|
textbox:ClearFocus()
|
|
if (not okey) then
|
|
print("error:", errormessage)
|
|
end
|
|
promptFrame:Hide()
|
|
end
|
|
end
|
|
|
|
buttonTrue:SetClickFunction(function()
|
|
executeCallback()
|
|
end)
|
|
|
|
textbox:SetHook("OnEnterPressed", function()
|
|
executeCallback()
|
|
end)
|
|
|
|
promptFrame:Hide()
|
|
detailsFramework.text_prompt_panel = promptFrame
|
|
end
|
|
|
|
detailsFramework.text_prompt_panel:Show()
|
|
DetailsFrameworkPrompt.EntryBox:SetText("")
|
|
detailsFramework.text_prompt_panel.prompt:SetText(message)
|
|
detailsFramework.text_prompt_panel.button_true.true_function = callback
|
|
detailsFramework.text_prompt_panel.textbox:SetFocus(true)
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--chart panel -- ~chart
|
|
|
|
local chart_panel_backdrop = {bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16,
|
|
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", edgeSize = 32, insets = {left = 5, right = 5, top = 5, bottom = 5}}
|
|
|
|
local chart_panel_align_timelabels = function(self, elapsed_time)
|
|
self.TimeScale = elapsed_time
|
|
|
|
local linha = self.TimeLabels[17]
|
|
local minutes, seconds = math.floor(elapsed_time / 60), math.floor(elapsed_time % 60)
|
|
if (seconds < 10) then
|
|
seconds = "0" .. seconds
|
|
end
|
|
|
|
if (minutes > 0) then
|
|
if (minutes < 10) then
|
|
minutes = "0" .. minutes
|
|
end
|
|
linha:SetText(minutes .. ":" .. seconds)
|
|
else
|
|
linha:SetText("00:" .. seconds)
|
|
end
|
|
|
|
local time_div = elapsed_time / 16 --786 -- 49.125
|
|
|
|
for i = 2, 16 do
|
|
local linha = self.TimeLabels [i]
|
|
local this_time = time_div * (i-1)
|
|
local minutes, seconds = math.floor(this_time / 60), math.floor(this_time % 60)
|
|
|
|
if (seconds < 10) then
|
|
seconds = "0" .. seconds
|
|
end
|
|
|
|
if (minutes > 0) then
|
|
if (minutes < 10) then
|
|
minutes = "0" .. minutes
|
|
end
|
|
linha:SetText(minutes .. ":" .. seconds)
|
|
else
|
|
linha:SetText("00:" .. seconds)
|
|
end
|
|
end
|
|
end
|
|
|
|
local chart_panel_set_scale = function(self, amt, func, text)
|
|
if (type(amt) ~= "number") then
|
|
return
|
|
end
|
|
|
|
--each line amount, then multiply the line index by this number
|
|
local piece = amt / 8
|
|
|
|
for i = 1, 8 do
|
|
if (func) then
|
|
self ["dpsamt" .. math.abs(i-9)]:SetText(func (piece*i))
|
|
else
|
|
if (piece*i > 1) then
|
|
self ["dpsamt" .. math.abs(i-9)]:SetText(detailsFramework.FormatNumber (piece*i))
|
|
else
|
|
self ["dpsamt" .. math.abs(i-9)]:SetText(format("%.3f", piece*i))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local chart_panel_can_move = function(self, can)
|
|
self.can_move = can
|
|
end
|
|
|
|
local chart_panel_overlay_reset = function(self)
|
|
self.OverlaysAmount = 1
|
|
for index, pack in ipairs(self.Overlays) do
|
|
for index2, texture in ipairs(pack) do
|
|
texture:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
local chart_panel_reset = function(self)
|
|
self.Graphic:ResetData()
|
|
self.Graphic.max_value = 0
|
|
|
|
self.TimeScale = nil
|
|
self.BoxLabelsAmount = 1
|
|
table.wipe(self.GData)
|
|
table.wipe(self.OData)
|
|
|
|
for index, box in ipairs(self.BoxLabels) do
|
|
box.check:Hide()
|
|
box.button:Hide()
|
|
box.box:Hide()
|
|
box.text:Hide()
|
|
box.border:Hide()
|
|
box.showing = false
|
|
end
|
|
|
|
chart_panel_overlay_reset (self)
|
|
end
|
|
|
|
local chart_panel_enable_line = function(f, thisbox)
|
|
local index = thisbox.index
|
|
local boxType = thisbox.type
|
|
|
|
if (thisbox.enabled) then
|
|
--disable
|
|
thisbox.check:Hide()
|
|
thisbox.enabled = false
|
|
else
|
|
--enable
|
|
thisbox.check:Show()
|
|
thisbox.enabled = true
|
|
end
|
|
|
|
if (boxType == "graphic") then
|
|
f.Graphic:ResetData()
|
|
f.Graphic.max_value = 0
|
|
|
|
local max = 0
|
|
local max_time = 0
|
|
|
|
for index, box in ipairs(f.BoxLabels) do
|
|
if (box.type == boxType and box.showing and box.enabled) then
|
|
local data = f.GData[index]
|
|
|
|
f.Graphic:AddDataSeries(data[1], data[2], nil, data[3])
|
|
|
|
if (data[4] > max) then
|
|
max = data[4]
|
|
end
|
|
if (data [5] > max_time) then
|
|
max_time = data [5]
|
|
end
|
|
end
|
|
end
|
|
|
|
f:SetScale(max)
|
|
f:SetTime (max_time)
|
|
|
|
elseif (boxType == "overlay") then
|
|
chart_panel_overlay_reset (f)
|
|
|
|
for index, box in ipairs(f.BoxLabels) do
|
|
if (box.type == boxType and box.showing and box.enabled) then
|
|
f:AddOverlay(box.index)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local create_box = function(self, next_box)
|
|
local thisbox = {}
|
|
self.BoxLabels [next_box] = thisbox
|
|
|
|
local box = detailsFramework:NewImage(self.Graphic, nil, 16, 16, "border")
|
|
local text = detailsFramework:NewLabel(self.Graphic)
|
|
|
|
local border = detailsFramework:NewImage(self.Graphic, [[Interface\DialogFrame\UI-DialogBox-Gold-Corner]], 30, 30, "artwork")
|
|
border:SetPoint("center", box, "center", -3, -4)
|
|
border:SetTexture([[Interface\DialogFrame\UI-DialogBox-Gold-Corner]])
|
|
|
|
local checktexture = detailsFramework:NewImage(self.Graphic, [[Interface\Buttons\UI-CheckBox-Check]], 18, 18, "overlay")
|
|
checktexture:SetPoint("center", box, "center", 0, -1)
|
|
checktexture:SetTexture([[Interface\Buttons\UI-CheckBox-Check]])
|
|
|
|
thisbox.box = box
|
|
thisbox.text = text
|
|
thisbox.border = border
|
|
thisbox.check = checktexture
|
|
thisbox.enabled = true
|
|
|
|
local button = CreateFrame("button", nil, self.Graphic, "BackdropTemplate")
|
|
button:SetSize(20, 20)
|
|
button:SetScript("OnClick", function()
|
|
chart_panel_enable_line (self, thisbox)
|
|
end)
|
|
button:SetPoint("topleft", box.widget or box, "topleft", 0, 0)
|
|
button:SetPoint("bottomright", box.widget or box, "bottomright", 0, 0)
|
|
|
|
button:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
|
button:SetBackdropColor(0, 0, 0, 0.0)
|
|
button:SetBackdropBorderColor(0, 0, 0, 1)
|
|
|
|
thisbox.button = button
|
|
|
|
thisbox.box:SetPoint("right", text, "left", -4, 0)
|
|
|
|
if (next_box == 1) then
|
|
thisbox.text:SetPoint("topright", self, "topright", -35, -16)
|
|
else
|
|
thisbox.text:SetPoint("right", self.BoxLabels [next_box-1].box, "left", -17, 0)
|
|
end
|
|
|
|
return thisbox
|
|
|
|
end
|
|
|
|
local realign_labels = function(self)
|
|
if (not self.ShowHeader) then
|
|
for _, box in ipairs(self.BoxLabels) do
|
|
box.check:Hide()
|
|
box.button:Hide()
|
|
box.border:Hide()
|
|
box.box:Hide()
|
|
box.text:Hide()
|
|
end
|
|
return
|
|
end
|
|
|
|
local width = self:GetWidth() - 108
|
|
|
|
local first_box = self.BoxLabels [1]
|
|
first_box.text:SetPoint("topright", self, "topright", -35, -16)
|
|
|
|
local line_width = first_box.text:GetStringWidth() + 26
|
|
|
|
for i = 2, #self.BoxLabels do
|
|
|
|
local box = self.BoxLabels [i]
|
|
|
|
if (box.box:IsShown()) then
|
|
|
|
line_width = line_width + box.text:GetStringWidth() + 26
|
|
|
|
if (line_width > width) then
|
|
line_width = box.text:GetStringWidth() + 26
|
|
box.text:SetPoint("topright", self, "topright", -35, -40)
|
|
else
|
|
box.text:SetPoint("right", self.BoxLabels [i-1].box, "left", -27, 0)
|
|
end
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
if (self.HeaderOnlyIndicator) then
|
|
for _, box in ipairs(self.BoxLabels) do
|
|
box.check:Hide()
|
|
box.button:Hide()
|
|
end
|
|
return
|
|
end
|
|
end
|
|
|
|
local chart_panel_add_label = function(self, color, name, type, number)
|
|
local next_box = self.BoxLabelsAmount
|
|
local thisbox = self.BoxLabels [next_box]
|
|
|
|
if (not thisbox) then
|
|
thisbox = create_box (self, next_box)
|
|
end
|
|
|
|
self.BoxLabelsAmount = self.BoxLabelsAmount + 1
|
|
|
|
thisbox.type = type
|
|
thisbox.index = number
|
|
|
|
thisbox.box:SetColorTexture(unpack(color))
|
|
thisbox.text:SetText(name)
|
|
|
|
thisbox.check:Show()
|
|
thisbox.button:Show()
|
|
thisbox.border:Hide()
|
|
thisbox.box:Show()
|
|
thisbox.text:Show()
|
|
|
|
thisbox.showing = true
|
|
thisbox.enabled = true
|
|
|
|
realign_labels(self)
|
|
end
|
|
|
|
local line_default_color = {1, 1, 1}
|
|
local draw_overlay = function(self, this_overlay, overlayData, color)
|
|
|
|
local pixel = self.Graphic:GetWidth() / self.TimeScale
|
|
local index = 1
|
|
local r, g, b, a = unpack(color or line_default_color)
|
|
|
|
for i = 1, #overlayData, 2 do
|
|
local aura_start = overlayData [i]
|
|
local aura_end = overlayData [i+1]
|
|
|
|
local this_block = this_overlay [index]
|
|
if (not this_block) then
|
|
this_block = self.Graphic:CreateTexture(nil, "border")
|
|
table.insert(this_overlay, this_block)
|
|
end
|
|
this_block:SetHeight(self.Graphic:GetHeight())
|
|
|
|
this_block:SetPoint("left", self.Graphic, "left", pixel * aura_start, 0)
|
|
if (aura_end) then
|
|
this_block:SetWidth((aura_end-aura_start)*pixel)
|
|
else
|
|
--malformed table
|
|
this_block:SetWidth(pixel*5)
|
|
end
|
|
|
|
this_block:SetColorTexture(r, g, b, a or 0.25)
|
|
this_block:Show()
|
|
|
|
index = index + 1
|
|
end
|
|
end
|
|
|
|
local chart_panel_add_overlay = function(self, overlayData, color, name, icon)
|
|
if (not self.TimeScale) then
|
|
error("Use SetTime (time) before adding an overlay.")
|
|
end
|
|
|
|
if (type(overlayData) == "number") then
|
|
local overlay_index = overlayData
|
|
draw_overlay (self, self.Overlays [self.OverlaysAmount], self.OData [overlay_index][1], self.OData [overlay_index][2])
|
|
else
|
|
local this_overlay = self.Overlays [self.OverlaysAmount]
|
|
if (not this_overlay) then
|
|
this_overlay = {}
|
|
table.insert(self.Overlays, this_overlay)
|
|
end
|
|
|
|
draw_overlay (self, this_overlay, overlayData, color)
|
|
|
|
table.insert(self.OData, {overlayData, color or line_default_color})
|
|
if (name and self.HeaderShowOverlays) then
|
|
self:AddLabel (color or line_default_color, name, "overlay", #self.OData)
|
|
end
|
|
end
|
|
|
|
self.OverlaysAmount = self.OverlaysAmount + 1
|
|
end
|
|
|
|
-- Define the tricube weight function
|
|
function calc_cubeweight (i, j, d)
|
|
local w = ( 1 - math.abs((j-i)/d)^3)^3
|
|
if w < 0 then
|
|
w = 0
|
|
end
|
|
return w
|
|
end
|
|
|
|
local calc_lowess_smoothing = function(self, data, bandwidth)
|
|
local length = #data
|
|
local newData = {}
|
|
|
|
for i = 1, length do
|
|
local A = 0
|
|
local B = 0
|
|
local C = 0
|
|
local D = 0
|
|
local E = 0
|
|
|
|
-- Calculate span of values to be included in the regression
|
|
local jmin = floor(i-bandwidth/2)
|
|
local jmax = ceil (i+bandwidth/2)
|
|
if jmin < 1 then
|
|
jmin = 1
|
|
end
|
|
if jmax > length then
|
|
jmax = length
|
|
end
|
|
|
|
-- For all the values in the span, compute the weight and then the linear fit
|
|
|
|
for j = jmin, jmax do
|
|
w = calc_cubeweight (i, j, bandwidth/2)
|
|
x = j
|
|
y = data [j]
|
|
|
|
A = A + w*x
|
|
B = B + w*y
|
|
C = C + w*x^2
|
|
D = D + w*x*y
|
|
E = E + w
|
|
end
|
|
|
|
-- Calculate a (slope) and b (offset) for the linear fit
|
|
local a = (A*B-D*E)/(A^2 - C*E)
|
|
local b = (A*D-B*C)/(A^2 - C*E)
|
|
|
|
-- Calculate the smoothed value by the formula y=a*x+b (x <- i)
|
|
newData [i] = a*i+b
|
|
end
|
|
return newData
|
|
end
|
|
|
|
local calc_stddev = function(self, data)
|
|
local total = 0
|
|
for i = 1, #data do
|
|
total = total + data[i]
|
|
end
|
|
local mean = total / #data
|
|
|
|
local totalDistance = 0
|
|
for i = 1, #data do
|
|
totalDistance = totalDistance + ((data[i] - mean) ^ 2)
|
|
end
|
|
|
|
local deviation = math.sqrt (totalDistance / #data)
|
|
return deviation
|
|
end
|
|
|
|
local SMA_table = {}
|
|
local SMA_max = 0
|
|
local reset_SMA = function()
|
|
table.wipe(SMA_table)
|
|
SMA_max = 0
|
|
end
|
|
|
|
local calc_SMA
|
|
calc_SMA = function(a, b, ...)
|
|
if (b) then
|
|
return calc_SMA (a + b, ...)
|
|
else
|
|
return a
|
|
end
|
|
end
|
|
|
|
local do_SMA = function(value, max_value)
|
|
if (#SMA_table == 10) then
|
|
tremove(SMA_table, 1)
|
|
end
|
|
|
|
SMA_table [#SMA_table + 1] = value
|
|
|
|
local new_value = calc_SMA (unpack(SMA_table)) / #SMA_table
|
|
|
|
if (new_value > SMA_max) then
|
|
SMA_max = new_value
|
|
return new_value, SMA_max
|
|
else
|
|
return new_value
|
|
end
|
|
end
|
|
|
|
local chart_panel_onresize = function(self)
|
|
local width, height = self:GetSize()
|
|
local spacement = width - 78 - 60
|
|
spacement = spacement / 16
|
|
|
|
for i = 1, 17 do
|
|
local label = self.TimeLabels [i]
|
|
label:SetPoint("bottomleft", self, "bottomleft", 78 + ((i-1)*spacement), self.TimeLabelsHeight)
|
|
label.line:SetHeight(height - 45)
|
|
end
|
|
|
|
local spacement = (self.Graphic:GetHeight()) / 8
|
|
for i = 1, 8 do
|
|
self ["dpsamt"..i]:SetPoint("TOPLEFT", self, "TOPLEFT", 27, -25 + (-(spacement* (i-1))) )
|
|
self ["dpsamt"..i].line:SetWidth(width-20)
|
|
end
|
|
|
|
self.Graphic:SetSize(width - 135, height - 67)
|
|
self.Graphic:SetPoint("topleft", self, "topleft", 108, -35)
|
|
end
|
|
|
|
local chart_panel_add_data = function(self, graphicData, color, name, elapsedTime, lineTexture, smoothLevel, firstIndex)
|
|
local chartPanel = self --chartPanel from the framework CreateChartPanel
|
|
local LibGraphChartFrame = self.Graphic
|
|
|
|
local builtData = {}
|
|
local maxValue = graphicData.max_value
|
|
local scaleWidth = 1 / LibGraphChartFrame:GetWidth()
|
|
local content = graphicData
|
|
|
|
--smooth the start and end of the chart
|
|
table.insert(content, 1, 0)
|
|
table.insert(content, 1, 0)
|
|
table.insert(content, #content+1, 0)
|
|
table.insert(content, #content+1, 0)
|
|
|
|
local index = 3
|
|
local graphMaxDps = math.max(LibGraphChartFrame.max_value, maxValue)
|
|
|
|
--do smoothness progress
|
|
if (not smoothLevel) then
|
|
while (index <= #content-2) do
|
|
local value = (content[index-2] + content[index-1] + content[index] + content[index+1] + content[index+2]) / 5 --normalize
|
|
builtData[#builtData+1] = {scaleWidth * (index-2), value / graphMaxDps} -- x and y coords
|
|
index = index + 1
|
|
end
|
|
|
|
elseif (smoothLevel == "SHORT") then
|
|
while (index <= #content-2) do
|
|
local value = (content[index] + content[index+1]) / 2
|
|
builtData [#builtData+1] = {scaleWidth*(index-2), value}
|
|
builtData [#builtData+1] = {scaleWidth*(index-2), value}
|
|
index = index + 2
|
|
end
|
|
|
|
elseif (smoothLevel == "SMA") then
|
|
reset_SMA()
|
|
while (index <= #content-2) do
|
|
local value, is_new_max_value = do_SMA(content[index], maxValue)
|
|
if (is_new_max_value) then
|
|
maxValue = is_new_max_value
|
|
end
|
|
builtData [#builtData+1] = {scaleWidth * (index-2), value} -- x and y coords
|
|
index = index + 1
|
|
end
|
|
|
|
elseif (smoothLevel == -1) then
|
|
while (index <= #content-2) do
|
|
local current = content[index]
|
|
|
|
local minus_2 = content[index-2] * 0.6
|
|
local minus_1 = content[index-1] * 0.8
|
|
local plus_1 = content[index+1] * 0.8
|
|
local plus_2 = content[index+2] * 0.6
|
|
|
|
local value = (current + minus_2 + minus_1 + plus_1 + plus_2) / 5 --normalize
|
|
builtData [#builtData+1] = {scaleWidth * (index-2), value / graphMaxDps} -- x and y coords
|
|
index = index + 1
|
|
end
|
|
|
|
elseif (smoothLevel == 1) then
|
|
index = 2
|
|
while (index <= #content-1) do
|
|
local value = (content[index-1]+content[index]+content[index+1])/3 --normalize
|
|
builtData [#builtData+1] = {scaleWidth*(index-1), value/graphMaxDps} -- x and y coords
|
|
index = index + 1
|
|
end
|
|
|
|
elseif (smoothLevel == 2) then
|
|
index = 1
|
|
while (index <= #content) do
|
|
local value = content[index] --do not normalize
|
|
builtData [#builtData+1] = {scaleWidth*(index), value/graphMaxDps} -- x and y coords
|
|
index = index + 1
|
|
end
|
|
end
|
|
|
|
tremove(content, 1)
|
|
tremove(content, 1)
|
|
tremove(content, #graphicData)
|
|
tremove(content, #graphicData)
|
|
|
|
if (maxValue > LibGraphChartFrame.max_value) then
|
|
--normalize previous data
|
|
if (LibGraphChartFrame.max_value > 0) then
|
|
local normalizePercent = LibGraphChartFrame.max_value / maxValue
|
|
for dataIndex, Data in ipairs(LibGraphChartFrame.Data) do
|
|
local Points = Data.Points
|
|
for i = 1, #Points do
|
|
Points[i][2] = Points[i][2] * normalizePercent
|
|
end
|
|
end
|
|
end
|
|
|
|
LibGraphChartFrame.max_value = maxValue
|
|
chartPanel:SetScale(maxValue)
|
|
end
|
|
|
|
table.insert(chartPanel.GData, {builtData, color or line_default_color, lineTexture, maxValue, elapsedTime})
|
|
if (name) then
|
|
chartPanel:AddLabel(color or line_default_color, name, "graphic", #chartPanel.GData)
|
|
end
|
|
|
|
local newLineTexture = "Interface\\AddOns\\Details\\Libs\\LibGraph-2.0\\line"
|
|
|
|
if (firstIndex) then
|
|
table.insert(LibGraphChartFrame.Data, 1, {Points = builtData, Color = color or line_default_color, lineTexture = newLineTexture, ElapsedTime = elapsedTime})
|
|
LibGraphChartFrame.NeedsUpdate = true
|
|
else
|
|
LibGraphChartFrame:AddDataSeries(builtData, color or line_default_color, nil, newLineTexture)
|
|
LibGraphChartFrame.Data[#LibGraphChartFrame.Data].ElapsedTime = elapsedTime
|
|
end
|
|
|
|
local maxTime = 0
|
|
for _, data in ipairs(LibGraphChartFrame.Data) do
|
|
if (data.ElapsedTime > maxTime) then
|
|
maxTime = data.ElapsedTime
|
|
end
|
|
end
|
|
|
|
chartPanel:SetTime(maxTime)
|
|
chart_panel_onresize(chartPanel)
|
|
end
|
|
|
|
|
|
local chart_panel_vlines_on = function(self)
|
|
for i = 1, 17 do
|
|
local label = self.TimeLabels[i]
|
|
label.line:Show()
|
|
end
|
|
end
|
|
|
|
local chart_panel_vlines_off = function(self)
|
|
for i = 1, 17 do
|
|
local label = self.TimeLabels[i]
|
|
label.line:Hide()
|
|
end
|
|
end
|
|
|
|
local chart_panel_set_title = function(self, title)
|
|
self.chart_title.text = title
|
|
end
|
|
|
|
local chart_panel_mousedown = function(self, button)
|
|
if (button == "LeftButton" and self.can_move) then
|
|
if (not self.isMoving) then
|
|
self:StartMoving()
|
|
self.isMoving = true
|
|
end
|
|
elseif (button == "RightButton" and not self.no_right_click_close) then
|
|
if (not self.isMoving) then
|
|
self:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
local chart_panel_mouseup = function(self, button)
|
|
if (button == "LeftButton" and self.isMoving) then
|
|
self:StopMovingOrSizing()
|
|
self.isMoving = nil
|
|
end
|
|
end
|
|
|
|
local chart_panel_hide_close_button = function(self)
|
|
self.CloseButton:Hide()
|
|
end
|
|
|
|
local chart_panel_right_click_close = function(self, value)
|
|
if (type(value) == "boolean") then
|
|
if (value) then
|
|
self.no_right_click_close = nil
|
|
else
|
|
self.no_right_click_close = true
|
|
end
|
|
end
|
|
end
|
|
|
|
function detailsFramework:CreateChartPanel(parent, width, height, name)
|
|
if (not name) then
|
|
name = "DFPanel" .. detailsFramework.PanelCounter
|
|
detailsFramework.PanelCounter = detailsFramework.PanelCounter + 1
|
|
end
|
|
|
|
parent = parent or UIParent
|
|
width = width or 800
|
|
height = height or 500
|
|
|
|
local chartFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
|
chartFrame:SetSize(width or 500, height or 400)
|
|
chartFrame:EnableMouse(true)
|
|
chartFrame:SetMovable(true)
|
|
|
|
chartFrame:SetScript("OnMouseDown", chart_panel_mousedown)
|
|
chartFrame:SetScript("OnMouseUp", chart_panel_mouseup)
|
|
|
|
chartFrame:SetBackdrop(chart_panel_backdrop)
|
|
chartFrame:SetBackdropColor(.3, .3, .3, .3)
|
|
|
|
local closeButton = CreateFrame("Button", nil, chartFrame, "UIPanelCloseButton", "BackdropTemplate")
|
|
closeButton:SetWidth(32)
|
|
closeButton:SetHeight(32)
|
|
closeButton:SetPoint("TOPRIGHT", chartFrame, "TOPRIGHT", -3, -7)
|
|
closeButton:SetFrameLevel(chartFrame:GetFrameLevel()+1)
|
|
closeButton:SetAlpha(0.9)
|
|
chartFrame.CloseButton = closeButton
|
|
|
|
local title = detailsFramework:NewLabel(chartFrame, nil, "$parentTitle", "chart_title", "Chart!", nil, 20, {1, 1, 0})
|
|
title:SetPoint("topleft", chartFrame, "topleft", 110, -13)
|
|
|
|
chartFrame.Overlays = {}
|
|
chartFrame.OverlaysAmount = 1
|
|
|
|
chartFrame.BoxLabels = {}
|
|
chartFrame.BoxLabelsAmount = 1
|
|
|
|
chartFrame.ShowHeader = true
|
|
chartFrame.HeaderOnlyIndicator = false
|
|
chartFrame.HeaderShowOverlays = true
|
|
|
|
--graphic
|
|
local g = LibStub:GetLibrary("LibGraph-2.0"):CreateGraphLine (name .. "Graphic", chartFrame, "topleft","topleft", 108, -35, width - 120, height - 67)
|
|
g:SetXAxis (-1,1)
|
|
g:SetYAxis (-1,1)
|
|
g:SetGridSpacing (false, false)
|
|
g:SetGridColor ({0.5,0.5,0.5,0.3})
|
|
g:SetAxisDrawing (false,false)
|
|
g:SetAxisColor({1.0,1.0,1.0,1.0})
|
|
g:SetAutoScale (true)
|
|
g:SetLineTexture ("smallline")
|
|
g:SetBorderSize ("right", 0.001)
|
|
g:SetBorderSize ("left", 0.000)
|
|
g:SetBorderSize ("top", 0.002)
|
|
g:SetBorderSize ("bottom", 0.001)
|
|
g.VerticalLines = {}
|
|
g.max_value = 0
|
|
|
|
g:SetLineTexture ("line")
|
|
|
|
chartFrame.Graphic = g
|
|
chartFrame.GData = {}
|
|
chartFrame.OData = {}
|
|
chartFrame.ChartFrames = {}
|
|
|
|
--div lines
|
|
for i = 1, 8, 1 do
|
|
local line = g:CreateTexture(nil, "overlay")
|
|
line:SetColorTexture(1, 1, 1, .05)
|
|
line:SetWidth(670)
|
|
line:SetHeight(1.1)
|
|
|
|
local s = chartFrame:CreateFontString(nil, "overlay", "GameFontHighlightSmall")
|
|
chartFrame ["dpsamt"..i] = s
|
|
s:SetText("100k")
|
|
s:SetPoint("topleft", chartFrame, "topleft", 27, -61 + (-(24.6*i)))
|
|
|
|
line:SetPoint("topleft", s, "bottom", -27, 0)
|
|
line:SetPoint("topright", g, "right", 0, 0)
|
|
s.line = line
|
|
end
|
|
|
|
--create time labels and the bottom texture to use as a background to these labels
|
|
chartFrame.TimeLabels = {}
|
|
chartFrame.TimeLabelsHeight = 16
|
|
|
|
for i = 1, 17 do
|
|
local timeString = chartFrame:CreateFontString(nil, "overlay", "GameFontHighlightSmall")
|
|
timeString:SetText("00:00")
|
|
timeString:SetPoint("bottomleft", chartFrame, "bottomleft", 78 + ((i-1)*36), chartFrame.TimeLabelsHeight)
|
|
chartFrame.TimeLabels [i] = timeString
|
|
|
|
local line = chartFrame:CreateTexture(nil, "border")
|
|
line:SetSize(1, height-45)
|
|
line:SetColorTexture(1, 1, 1, .1)
|
|
line:SetPoint("bottomleft", timeString, "topright", 0, -10)
|
|
line:Hide()
|
|
timeString.line = line
|
|
end
|
|
|
|
local bottom_texture = detailsFramework:NewImage(chartFrame, nil, 702, 25, "background", nil, nil, "$parentBottomTexture")
|
|
bottom_texture:SetColorTexture(.1, .1, .1, .7)
|
|
bottom_texture:SetPoint("topright", g, "bottomright", 0, 0)
|
|
bottom_texture:SetPoint("bottomleft", chartFrame, "bottomleft", 8, 12)
|
|
|
|
|
|
|
|
chartFrame.SetTime = chart_panel_align_timelabels
|
|
chartFrame.EnableVerticalLines = chart_panel_vlines_on
|
|
chartFrame.DisableVerticalLines = chart_panel_vlines_off
|
|
chartFrame.SetTitle = chart_panel_set_title
|
|
chartFrame.SetScale = chart_panel_set_scale
|
|
chartFrame.Reset = chart_panel_reset
|
|
chartFrame.AddLine = chart_panel_add_data
|
|
chartFrame.CanMove = chart_panel_can_move
|
|
chartFrame.AddLabel = chart_panel_add_label
|
|
chartFrame.AddOverlay = chart_panel_add_overlay
|
|
chartFrame.HideCloseButton = chart_panel_hide_close_button
|
|
chartFrame.RightClickClose = chart_panel_right_click_close
|
|
chartFrame.CalcStdDev = calc_stddev
|
|
chartFrame.CalcLowessSmoothing = calc_lowess_smoothing
|
|
|
|
chartFrame:SetScript("OnSizeChanged", chart_panel_onresize)
|
|
chart_panel_onresize(chartFrame)
|
|
|
|
return chartFrame
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- ~gframe
|
|
local gframe_on_enter_line = function(self)
|
|
self:SetBackdropColor(0, 0, 0, 0)
|
|
|
|
local parent = self:GetParent()
|
|
local ball = self.ball
|
|
ball:SetBlendMode("ADD")
|
|
|
|
local on_enter = parent._onenter_line
|
|
if (on_enter) then
|
|
return on_enter (self, parent)
|
|
end
|
|
end
|
|
|
|
local gframe_on_leave_line = function(self)
|
|
self:SetBackdropColor(0, 0, 0, .6)
|
|
|
|
local parent = self:GetParent()
|
|
local ball = self.ball
|
|
ball:SetBlendMode("BLEND")
|
|
|
|
local on_leave = parent._onleave_line
|
|
if (on_leave) then
|
|
return on_leave (self, parent)
|
|
end
|
|
end
|
|
|
|
local gframe_create_line = function(self)
|
|
local index = #self._lines+1
|
|
|
|
local f = CreateFrame("frame", nil, self, "BackdropTemplate")
|
|
self._lines [index] = f
|
|
f.id = index
|
|
f:SetScript("OnEnter", gframe_on_enter_line)
|
|
f:SetScript("OnLeave", gframe_on_leave_line)
|
|
|
|
f:SetWidth(self._linewidth)
|
|
|
|
if (index == 1) then
|
|
f:SetPoint("topleft", self, "topleft")
|
|
f:SetPoint("bottomleft", self, "bottomleft")
|
|
else
|
|
local previous_line = self._lines [index-1]
|
|
f:SetPoint("topleft", previous_line, "topright")
|
|
f:SetPoint("bottomleft", previous_line, "bottomright")
|
|
end
|
|
|
|
local t = f:CreateTexture(nil, "background")
|
|
t:SetWidth(1)
|
|
t:SetPoint("topright", f, "topright")
|
|
t:SetPoint("bottomright", f, "bottomright")
|
|
t:SetColorTexture(1, 1, 1, .1)
|
|
f.grid = t
|
|
|
|
local b = f:CreateTexture(nil, "overlay")
|
|
b:SetTexture([[Interface\COMMON\Indicator-Yellow]])
|
|
b:SetSize(16, 16)
|
|
f.ball = b
|
|
local anchor = CreateFrame("frame", nil, f, "BackdropTemplate")
|
|
anchor:SetAllPoints(b)
|
|
b.tooltip_anchor = anchor
|
|
|
|
local spellicon = f:CreateTexture(nil, "artwork")
|
|
spellicon:SetPoint("bottom", b, "bottom", 0, 10)
|
|
spellicon:SetSize(16, 16)
|
|
f.spellicon = spellicon
|
|
|
|
local text = f:CreateFontString(nil, "overlay", "GameFontNormal")
|
|
local textBackground = f:CreateTexture(nil, "artwork")
|
|
textBackground:SetSize(30, 16)
|
|
textBackground:SetColorTexture(0, 0, 0, 0.5)
|
|
textBackground:SetPoint("bottom", f.ball, "top", 0, -6)
|
|
text:SetPoint("center", textBackground, "center")
|
|
detailsFramework:SetFontSize(text, 10)
|
|
f.text = text
|
|
f.textBackground = textBackground
|
|
|
|
local timeline = f:CreateFontString(nil, "overlay", "GameFontNormal")
|
|
timeline:SetPoint("bottomright", f, "bottomright", -2, 0)
|
|
detailsFramework:SetFontSize(timeline, 8)
|
|
f.timeline = timeline
|
|
|
|
return f
|
|
end
|
|
|
|
local gframe_getline = function(self, index)
|
|
local line = self._lines [index]
|
|
if (not line) then
|
|
line = gframe_create_line (self)
|
|
end
|
|
return line
|
|
end
|
|
|
|
local gframe_reset = function(self)
|
|
for i, line in ipairs(self._lines) do
|
|
line:Hide()
|
|
end
|
|
if (self.GraphLib_Lines_Used) then
|
|
for i = #self.GraphLib_Lines_Used, 1, -1 do
|
|
local line = tremove(self.GraphLib_Lines_Used)
|
|
table.insert(self.GraphLib_Lines, line)
|
|
line:Hide()
|
|
end
|
|
end
|
|
end
|
|
|
|
local gframe_update = function(self, lines)
|
|
local g = LibStub:GetLibrary ("LibGraph-2.0")
|
|
local h = self:GetHeight()/100
|
|
local amtlines = #lines
|
|
local linewidth = self._linewidth
|
|
|
|
local max_value = 0
|
|
for i = 1, amtlines do
|
|
if (lines [i].value > max_value) then
|
|
max_value = lines [i].value
|
|
end
|
|
end
|
|
|
|
self.MaxValue = max_value
|
|
|
|
local o = 1
|
|
local lastvalue = self:GetHeight()/2
|
|
max_value = math.max(max_value, 0.0000001)
|
|
|
|
for i = 1, min (amtlines, self._maxlines) do
|
|
|
|
local data = lines [i]
|
|
|
|
local pvalue = data.value / max_value * 100
|
|
if (pvalue > 98) then
|
|
pvalue = 98
|
|
end
|
|
pvalue = pvalue * h
|
|
|
|
g:DrawLine (self, (o-1)*linewidth, lastvalue, o*linewidth, pvalue, linewidth, {1, 1, 1, 1}, "overlay")
|
|
lastvalue = pvalue
|
|
|
|
local line = self:GetLine (i)
|
|
line:Show()
|
|
line.ball:Show()
|
|
|
|
line.ball:SetPoint("bottomleft", self, "bottomleft", (o*linewidth)-8, pvalue-8)
|
|
line.spellicon:SetTexture(nil)
|
|
line.timeline:SetText(data.text)
|
|
line.timeline:Show()
|
|
|
|
if (data.utext) then
|
|
line.text:Show()
|
|
line.textBackground:Show()
|
|
line.text:SetText(data.utext)
|
|
else
|
|
line.text:Hide()
|
|
line.textBackground:Hide()
|
|
end
|
|
|
|
line.data = data
|
|
|
|
o = o + 1
|
|
end
|
|
end
|
|
|
|
function detailsFramework:CreateGFrame(parent, width, height, lineWidth, onEnter, onLeave, member, name)
|
|
local newGraphicFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
|
newGraphicFrame:SetSize(width or 450, height or 150)
|
|
|
|
if (member) then
|
|
parent[member] = newGraphicFrame
|
|
end
|
|
|
|
newGraphicFrame.CreateLine = gframe_create_line
|
|
newGraphicFrame.GetLine = gframe_getline
|
|
newGraphicFrame.Reset = gframe_reset
|
|
newGraphicFrame.UpdateLines = gframe_update
|
|
|
|
newGraphicFrame.MaxValue = 0
|
|
|
|
newGraphicFrame._lines = {}
|
|
|
|
newGraphicFrame._onenter_line = onEnter
|
|
newGraphicFrame._onleave_line = onLeave
|
|
|
|
newGraphicFrame._linewidth = lineWidth or 50
|
|
newGraphicFrame._maxlines = floor(newGraphicFrame:GetWidth() / newGraphicFrame._linewidth)
|
|
|
|
return newGraphicFrame
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--options tabs and buttons -dot
|
|
|
|
function detailsFramework:FindHighestParent(self)
|
|
local highestParent
|
|
if (self:GetParent() == UIParent) then
|
|
highestParent = self
|
|
end
|
|
|
|
if (not highestParent) then
|
|
highestParent = self
|
|
for i = 1, 6 do
|
|
local parent = highestParent:GetParent()
|
|
if (parent == UIParent) then
|
|
break
|
|
else
|
|
highestParent = parent
|
|
end
|
|
end
|
|
end
|
|
|
|
return highestParent
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- ~right ~click to ~close
|
|
|
|
function detailsFramework:CreateRightClickToClose(parent, xOffset, yOffset, color, fontSize)
|
|
--default values
|
|
xOffset = xOffset or 0
|
|
yOffset = yOffset or 0
|
|
color = color or "white"
|
|
fontSize = fontSize or 10
|
|
|
|
local label = detailsFramework:CreateLabel(parent, "right click to close", fontSize, color)
|
|
label:SetPoint("bottomright", parent, "bottomright", -4 + xOffset, 5 + yOffset)
|
|
|
|
return label
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- ~listbox
|
|
|
|
local simple_list_box_ResetWidgets = function(self)
|
|
for _, widget in ipairs(self.widgets) do
|
|
widget:Hide()
|
|
end
|
|
self.nextWidget = 1
|
|
end
|
|
|
|
local simple_list_box_onenter = function(self, capsule)
|
|
self:GetParent().options.onenter (self, capsule, capsule.value)
|
|
end
|
|
|
|
local simple_list_box_onleave = function(self, capsule)
|
|
self:GetParent().options.onleave (self, capsule, capsule.value)
|
|
GameTooltip:Hide()
|
|
end
|
|
|
|
local simple_list_box_GetOrCreateWidget = function(self)
|
|
local index = self.nextWidget
|
|
local widget = self.widgets [index]
|
|
if (not widget) then
|
|
widget = detailsFramework:CreateButton(self, function()end, self.options.width, self.options.row_height, "", nil, nil, nil, nil, nil, nil, detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"))
|
|
widget:SetHook("OnEnter", simple_list_box_onenter)
|
|
widget:SetHook("OnLeave", simple_list_box_onleave)
|
|
widget.textcolor = self.options.textcolor
|
|
widget.textsize = self.options.text_size
|
|
widget.onleave_backdrop = self.options.backdrop_color
|
|
|
|
widget.XButton = detailsFramework:CreateButton(widget, function()end, 16, 16)
|
|
widget.XButton:SetPoint("topright", widget.widget, "topright")
|
|
widget.XButton:SetIcon ([[Interface\BUTTONS\UI-Panel-MinimizeButton-Up]], 16, 16, "overlay", nil, nil, 0, -4, 0, false)
|
|
widget.XButton.icon:SetDesaturated(true)
|
|
|
|
if (not self.options.show_x_button) then
|
|
widget.XButton:Hide()
|
|
end
|
|
|
|
table.insert(self.widgets, widget)
|
|
end
|
|
self.nextWidget = self.nextWidget + 1
|
|
return widget
|
|
end
|
|
|
|
local simple_list_box_RefreshWidgets = function(self)
|
|
self:ResetWidgets()
|
|
local amt = 0
|
|
for value, _ in pairs(self.list_table) do
|
|
local widget = self:GetOrCreateWidget()
|
|
widget:SetPoint("topleft", self, "topleft", 1, -self.options.row_height * (self.nextWidget-2) - 4)
|
|
widget:SetPoint("topright", self, "topright", -1, -self.options.row_height * (self.nextWidget-2) - 4)
|
|
|
|
widget:SetClickFunction(self.func, value)
|
|
|
|
if (self.options.show_x_button) then
|
|
widget.XButton:SetClickFunction(self.options.x_button_func, value)
|
|
widget.XButton.value = value
|
|
widget.XButton:Show()
|
|
else
|
|
widget.XButton:Hide()
|
|
end
|
|
|
|
widget.value = value
|
|
|
|
if (self.options.icon) then
|
|
if (type(self.options.icon) == "string" or type(self.options.icon) == "number") then
|
|
local coords = type(self.options.iconcoords) == "table" and self.options.iconcoords or {0, 1, 0, 1}
|
|
widget:SetIcon (self.options.icon, self.options.row_height - 2, self.options.row_height - 2, "overlay", coords)
|
|
|
|
elseif (type(self.options.icon) == "function") then
|
|
local icon = self.options.icon (value)
|
|
if (icon) then
|
|
local coords = type(self.options.iconcoords) == "table" and self.options.iconcoords or {0, 1, 0, 1}
|
|
widget:SetIcon (icon, self.options.row_height - 2, self.options.row_height - 2, "overlay", coords)
|
|
end
|
|
end
|
|
else
|
|
widget:SetIcon ("", self.options.row_height, self.options.row_height)
|
|
end
|
|
|
|
if (self.options.text) then
|
|
if (type(self.options.text) == "function") then
|
|
local text = self.options.text (value)
|
|
if (text) then
|
|
widget:SetText(text)
|
|
else
|
|
widget:SetText("")
|
|
end
|
|
else
|
|
widget:SetText(self.options.text or "")
|
|
end
|
|
else
|
|
widget:SetText("")
|
|
end
|
|
|
|
widget.value = value
|
|
|
|
local r, g, b, a = detailsFramework:ParseColors(self.options.backdrop_color)
|
|
widget:SetBackdropColor(r, g, b, a)
|
|
|
|
widget:Show()
|
|
amt = amt + 1
|
|
end
|
|
if (amt == 0) then
|
|
self.EmptyLabel:Show()
|
|
else
|
|
self.EmptyLabel:Hide()
|
|
end
|
|
end
|
|
|
|
local backdrop = {bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16, edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1}
|
|
local default_options = {
|
|
height = 400,
|
|
row_height = 16,
|
|
width = 230,
|
|
icon = false,
|
|
text = "",
|
|
text_size = 10,
|
|
textcolor = "wheat",
|
|
|
|
backdrop_color = {1, 1, 1, .5},
|
|
panel_border_color = {0, 0, 0, 0.5},
|
|
|
|
onenter = function(self, capsule)
|
|
if (capsule) then
|
|
capsule.textcolor = "white"
|
|
end
|
|
end,
|
|
onleave = function(self, capsule)
|
|
if (capsule) then
|
|
capsule.textcolor = self:GetParent().options.textcolor
|
|
end
|
|
GameTooltip:Hide()
|
|
end,
|
|
}
|
|
|
|
local simple_list_box_SetData = function(self, t)
|
|
self.list_table = t
|
|
end
|
|
|
|
function detailsFramework:CreateSimpleListBox(parent, name, title, emptyText, listTable, onClick, options)
|
|
local scroll = CreateFrame("frame", name, parent, "BackdropTemplate")
|
|
|
|
scroll.ResetWidgets = simple_list_box_ResetWidgets
|
|
scroll.GetOrCreateWidget = simple_list_box_GetOrCreateWidget
|
|
scroll.Refresh = simple_list_box_RefreshWidgets
|
|
scroll.SetData = simple_list_box_SetData
|
|
scroll.nextWidget = 1
|
|
scroll.list_table = listTable
|
|
|
|
scroll.func = function(self, button, value)
|
|
detailsFramework:QuickDispatch(onClick, value)
|
|
scroll:Refresh()
|
|
end
|
|
scroll.widgets = {}
|
|
|
|
detailsFramework:ApplyStandardBackdrop(scroll)
|
|
|
|
scroll.options = options or {}
|
|
self.table.deploy(scroll.options, default_options)
|
|
|
|
if (scroll.options.x_button_func) then
|
|
local original_X_function = scroll.options.x_button_func
|
|
scroll.options.x_button_func = function(self, button, value)
|
|
detailsFramework:QuickDispatch(original_X_function, value)
|
|
scroll:Refresh()
|
|
end
|
|
end
|
|
|
|
scroll:SetBackdropBorderColor(unpack(scroll.options.panel_border_color))
|
|
|
|
scroll:SetSize(scroll.options.width + 2, scroll.options.height)
|
|
|
|
local name = detailsFramework:CreateLabel(scroll, title, 12, "silver")
|
|
name:SetTemplate(detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE"))
|
|
name:SetPoint("bottomleft", scroll, "topleft", 0, 2)
|
|
scroll.Title = name
|
|
|
|
local emptyLabel = detailsFramework:CreateLabel(scroll, emptyText, 12, "gray")
|
|
emptyLabel:SetAlpha(.6)
|
|
emptyLabel:SetSize(scroll.options.width-10, scroll.options.height)
|
|
emptyLabel:SetPoint("center", 0, 0)
|
|
emptyLabel:Hide()
|
|
emptyLabel.align = "center"
|
|
scroll.EmptyLabel = emptyLabel
|
|
|
|
return scroll
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- ~scrollbox
|
|
|
|
---@class df_scrollbox : scrollframe, df_sortmixin, df_scrollboxmixin
|
|
---@field data table
|
|
---@field Header df_headerframe?
|
|
---@field LineAmount number
|
|
---@field LineHeight number
|
|
---@field IsFauxScroll boolean?
|
|
---@field HideScrollBar boolean?
|
|
---@field Frames frame[]
|
|
---@field ReajustNumFrames boolean?
|
|
---@field DontHideChildrenOnPreRefresh boolean
|
|
---@field refresh_func fun(self:df_scrollbox, data:table, offset:number, numlines:number)
|
|
---@field Refresh fun(self:df_scrollbox)
|
|
---@field CreateLineFunc fun(self:df_scrollbox, index:number)?
|
|
---@field CreateLine fun(self:df_scrollbox, func:function)
|
|
---@field SetData fun(self:df_scrollbox, data:table)
|
|
---@field GetData fun(self:df_scrollbox): table
|
|
---@field OnSetData fun(self:df_scrollbox, data:table)? if exists, this function is called after the SetData with the same parameters
|
|
---@field
|
|
|
|
---create a scrollbox with the methods :Refresh() :SetData() :CreateLine()
|
|
---@param parent table
|
|
---@param name string
|
|
---@param refreshFunc function
|
|
---@param data table
|
|
---@param width number
|
|
---@param height number
|
|
---@param lineAmount number
|
|
---@param lineHeight number
|
|
---@param createLineFunc function?
|
|
---@param autoAmount boolean?
|
|
---@param noScroll boolean?
|
|
---@param noBackdrop boolean?
|
|
---@return df_scrollbox
|
|
function detailsFramework:CreateScrollBox(parent, name, refreshFunc, data, width, height, lineAmount, lineHeight, createLineFunc, autoAmount, noScroll, noBackdrop)
|
|
--create the scrollframe, it is the base of the scrollbox
|
|
---@type df_scrollbox
|
|
local scroll = CreateFrame("scrollframe", name, parent, "FauxScrollFrameTemplate, BackdropTemplate")
|
|
|
|
--apply the standard background color
|
|
if (not noBackdrop) then
|
|
detailsFramework:ApplyStandardBackdrop(scroll)
|
|
end
|
|
|
|
scroll:SetSize(width, height)
|
|
scroll.LineAmount = lineAmount
|
|
scroll.LineHeight = lineHeight
|
|
scroll.IsFauxScroll = true
|
|
scroll.HideScrollBar = noScroll
|
|
scroll.Frames = {}
|
|
scroll.ReajustNumFrames = autoAmount
|
|
scroll.CreateLineFunc = createLineFunc
|
|
scroll.DontHideChildrenOnPreRefresh = false
|
|
|
|
detailsFramework:Mixin(scroll, detailsFramework.SortFunctions)
|
|
detailsFramework:Mixin(scroll, detailsFramework.ScrollBoxFunctions)
|
|
|
|
scroll.refresh_func = refreshFunc
|
|
scroll.data = data
|
|
|
|
scroll:SetScript("OnVerticalScroll", scroll.OnVerticalScroll)
|
|
scroll:SetScript("OnSizeChanged", detailsFramework.ScrollBoxFunctions.OnSizeChanged)
|
|
|
|
return scroll
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- ~resizers
|
|
|
|
--these options are copied to the object with object:BuildOptionsTable()
|
|
local rezieGripOptions = {
|
|
width = 32,
|
|
height = 32,
|
|
should_mirror_left_texture = true,
|
|
normal_texture = [[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Up]],
|
|
highlight_texture = [[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Highlight]],
|
|
pushed_texture = [[Interface\CHATFRAME\UI-ChatIM-SizeGrabber-Down]],
|
|
}
|
|
|
|
---create the two resize grips for a frame, one in the bottom left and another in the bottom right
|
|
---@param parent frame
|
|
---@param options table|nil
|
|
---@param leftResizerName string|nil
|
|
---@param rightResizerName string|nil
|
|
---@return frame, frame
|
|
function detailsFramework:CreateResizeGrips(parent, options, leftResizerName, rightResizerName)
|
|
local parentName = parent:GetName()
|
|
|
|
local leftResizer = _G.CreateFrame("button", leftResizerName or (parentName and "$parentLeftResizer"), parent, "BackdropTemplate")
|
|
local rightResizer = _G.CreateFrame("button", rightResizerName or (parentName and "$parentRightResizer"), parent, "BackdropTemplate")
|
|
|
|
detailsFramework:Mixin(leftResizer, detailsFramework.OptionsFunctions)
|
|
detailsFramework:Mixin(rightResizer, detailsFramework.OptionsFunctions)
|
|
leftResizer:BuildOptionsTable(rezieGripOptions, options)
|
|
rightResizer:BuildOptionsTable(rezieGripOptions, options)
|
|
|
|
leftResizer:SetPoint("bottomleft", parent, "bottomleft", 0, 0)
|
|
rightResizer:SetPoint("bottomright", parent, "bottomright", 0, 0)
|
|
leftResizer:SetSize(leftResizer.options.width, leftResizer.options.height)
|
|
rightResizer:SetSize(leftResizer.options.width, leftResizer.options.height)
|
|
|
|
rightResizer:SetNormalTexture(rightResizer.options.normal_texture)
|
|
rightResizer:SetHighlightTexture(rightResizer.options.highlight_texture)
|
|
rightResizer:SetPushedTexture(rightResizer.options.pushed_texture)
|
|
|
|
leftResizer:SetNormalTexture(leftResizer.options.normal_texture)
|
|
leftResizer:SetHighlightTexture(leftResizer.options.highlight_texture)
|
|
leftResizer:SetPushedTexture(leftResizer.options.pushed_texture)
|
|
|
|
if (leftResizer.options.should_mirror_left_texture) then
|
|
leftResizer:GetNormalTexture():SetTexCoord(1, 0, 0, 1)
|
|
leftResizer:GetHighlightTexture():SetTexCoord(1, 0, 0, 1)
|
|
leftResizer:GetPushedTexture():SetTexCoord(1, 0, 0, 1)
|
|
end
|
|
|
|
return leftResizer, rightResizer
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- ~standard backdrop
|
|
---this is the standard backdrop for detailsframework, it's a dark-ish color semi transparent with a thin opaque black border
|
|
---for the background it uses UI-Tooltip-Background with detailsFramework:GetDefaultBackdropColor() color
|
|
---for the border it uses Interface\Buttons\WHITE8X8
|
|
---also creates an additional texture frame.__background = texture with the same setting of the backdrop background
|
|
---@param self table
|
|
---@param frame frame
|
|
---@param bUseSolidColor boolean?
|
|
---@param alphaScale number?
|
|
function detailsFramework:ApplyStandardBackdrop(frame, bUseSolidColor, alphaScale)
|
|
alphaScale = alphaScale or 0.95
|
|
|
|
if (not frame.SetBackdrop)then
|
|
--print(debugstack(1,2,1))
|
|
Mixin(frame, BackdropTemplateMixin)
|
|
end
|
|
|
|
local red, green, blue, alpha = detailsFramework:GetDefaultBackdropColor()
|
|
|
|
if (bUseSolidColor) then
|
|
frame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Buttons\WHITE8X8]], tileSize = 32, tile = true})
|
|
frame:SetBackdropColor(red, green, blue, 0.872)
|
|
frame:SetBackdropBorderColor(0, 0, 0, 0.95)
|
|
|
|
else
|
|
frame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
|
frame:SetBackdropColor(red, green, blue, alpha * alphaScale)
|
|
frame:SetBackdropBorderColor(0, 0, 0, 0.95)
|
|
end
|
|
|
|
if (not frame.__background) then
|
|
frame.__background = frame:CreateTexture(nil, "border", nil, -6)
|
|
frame.__background:SetColorTexture(red, green, blue)
|
|
frame.__background:SetAllPoints()
|
|
end
|
|
|
|
frame.__background:SetAlpha(alpha * alphaScale)
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- ~title bar
|
|
|
|
detailsFramework.TitleFunctions = {
|
|
SetTitle = function(self, titleText, titleColor, font, size)
|
|
local titleLabel = self.TitleLabel or self.Text
|
|
|
|
titleLabel:SetText(titleText or titleLabel:GetText())
|
|
|
|
if (titleColor) then
|
|
local r, g, b, a = detailsFramework:ParseColors(titleColor)
|
|
titleLabel:SetTextColor(r, g, b, a)
|
|
end
|
|
|
|
if (font) then
|
|
detailsFramework:SetFontFace (titleLabel, font)
|
|
end
|
|
|
|
if (size) then
|
|
detailsFramework:SetFontSize(titleLabel, size)
|
|
end
|
|
end
|
|
}
|
|
|
|
---@class df_titlebar : frame
|
|
---@field TitleBar frame
|
|
---@field TitleLabel fontstring
|
|
---@field CloseButton button
|
|
---@field SetTitle fun(self:df_titlebar, titleText:string, titleColor:any, font:string, size:number)
|
|
|
|
---create a title bar with a font string in the center and a close button in the right side
|
|
---@param parent frame
|
|
---@param titleText string
|
|
---@return df_titlebar
|
|
function detailsFramework:CreateTitleBar(parent, titleText)
|
|
local titleBar = CreateFrame("frame", parent:GetName() and parent:GetName() .. "TitleBar" or nil, parent, "BackdropTemplate")
|
|
titleBar:SetPoint("topleft", parent, "topleft", 2, -3)
|
|
titleBar:SetPoint("topright", parent, "topright", -2, -3)
|
|
titleBar:SetHeight(20)
|
|
titleBar:SetBackdrop(SimplePanel_frame_backdrop) --it's an upload from this file
|
|
titleBar:SetBackdropColor(.2, .2, .2, 1)
|
|
titleBar:SetBackdropBorderColor(0, 0, 0, 1)
|
|
|
|
local closeButton = CreateFrame("button", titleBar:GetName() and titleBar:GetName() .. "CloseButton" or nil, titleBar, "BackdropTemplate")
|
|
closeButton:SetSize(16, 16)
|
|
|
|
closeButton:SetNormalTexture([[Interface\GLUES\LOGIN\Glues-CheckBox-Check]])
|
|
closeButton:SetHighlightTexture([[Interface\GLUES\LOGIN\Glues-CheckBox-Check]])
|
|
closeButton:SetPushedTexture([[Interface\GLUES\LOGIN\Glues-CheckBox-Check]])
|
|
closeButton:GetNormalTexture():SetDesaturated(true)
|
|
closeButton:GetHighlightTexture():SetDesaturated(true)
|
|
closeButton:GetPushedTexture():SetDesaturated(true)
|
|
|
|
closeButton:SetAlpha(0.7)
|
|
closeButton:SetScript("OnClick", simple_panel_close_click) --upvalue from this file
|
|
|
|
local titleLabel = titleBar:CreateFontString(titleBar:GetName() and titleBar:GetName() .. "TitleText" or nil, "overlay", "GameFontNormal")
|
|
titleLabel:SetTextColor(detailsFramework:ParseColors("gold"))
|
|
titleLabel:SetText(titleText or "")
|
|
|
|
--anchors
|
|
closeButton:SetPoint("right", titleBar, "right", -2, 0)
|
|
titleLabel:SetPoint("center", titleBar, "center")
|
|
|
|
--members
|
|
parent.TitleBar = titleBar
|
|
parent.CloseButton = closeButton
|
|
parent.TitleLabel = titleLabel
|
|
parent.SetTitle = titleBar.SetTitle
|
|
|
|
titleBar.TitleBar = titleBar --to fit documentation
|
|
titleBar.CloseButton = closeButton
|
|
titleBar.Text = titleLabel
|
|
|
|
detailsFramework:Mixin(parent, detailsFramework.TitleFunctions)
|
|
|
|
return titleBar
|
|
end
|
|
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--radio group
|
|
|
|
local default_radiogroup_options = {
|
|
width = 1,
|
|
height = 1,
|
|
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
backdrop_color = {0, 0, 0, 0.2},
|
|
backdrop_border_color = {0.1, 0.1, 0.1, .2},
|
|
is_radio = false,
|
|
text_color = {1, 0.8196, 0, 1},
|
|
text_size = 10,
|
|
text_outline = "NONE",
|
|
}
|
|
|
|
---@class df_radiogroup_checkbox : df_checkbox
|
|
---@field Label df_label
|
|
---@field Icon texture
|
|
---@field _optionid number
|
|
---@field _set function
|
|
---@field _callback function
|
|
---@field __width number
|
|
---@field __height number
|
|
|
|
---@class df_radiogroupmixin : table
|
|
---@field allCheckBoxes df_radiogroup_checkbox[]
|
|
---@field SetFadeState fun(self:df_checkboxgroup, state:boolean)
|
|
---@field Disable fun(self:df_checkboxgroup)
|
|
---@field Enable fun(self:df_checkboxgroup)
|
|
---@field DeselectAll fun(self:df_checkboxgroup)
|
|
---@field Select fun(self:df_checkboxgroup, checkboxId:number)
|
|
---@field GetSelected fun(self:df_checkboxgroup):number
|
|
---@field FadeIn fun(self:df_checkboxgroup)
|
|
---@field FadeOut fun(self:df_checkboxgroup)
|
|
---@field GetAllCheckboxes fun(self:df_checkboxgroup):df_radiogroup_checkbox[]
|
|
---@field GetCheckbox fun(self:df_checkboxgroup, checkboxId:number):df_radiogroup_checkbox
|
|
---@field CreateCheckbox fun(self:df_checkboxgroup):df_radiogroup_checkbox
|
|
---@field ResetAllCheckboxes fun(self:df_checkboxgroup)
|
|
---@field RadioOnClick fun(checkbox:df_radiogroup_checkbox, fixedParam:any, value:boolean)
|
|
---@field RefreshCheckbox fun(self:df_checkboxgroup, checkbox:df_radiogroup_checkbox, optionTable:table, optionId:number)
|
|
|
|
---@type df_radiogroupmixin
|
|
detailsFramework.RadioGroupCoreFunctions = {
|
|
allCheckBoxes = {},
|
|
|
|
Disable = function(self)
|
|
local checkBoxList = self:GetAllCheckboxes()
|
|
for _, checkbox in ipairs(checkBoxList) do
|
|
checkbox:Disable()
|
|
end
|
|
end,
|
|
|
|
Enable = function(self)
|
|
local checkBoxList = self:GetAllCheckboxes()
|
|
for _, checkbox in ipairs(checkBoxList) do
|
|
checkbox:Enable()
|
|
end
|
|
end,
|
|
|
|
DeselectAll = function(self)
|
|
local checkBoxList = self:GetAllCheckboxes()
|
|
for _, checkbox in ipairs(checkBoxList) do
|
|
checkbox:SetValue(false)
|
|
end
|
|
end,
|
|
|
|
FadeIn = function(self)
|
|
local checkBoxList = self:GetAllCheckboxes()
|
|
for _, checkbox in ipairs(checkBoxList) do
|
|
checkbox:SetAlpha(1)
|
|
end
|
|
end,
|
|
|
|
FadeOut = function(self)
|
|
local checkBoxList = self:GetAllCheckboxes()
|
|
for _, checkbox in ipairs(checkBoxList) do
|
|
checkbox:SetAlpha(.7)
|
|
end
|
|
end,
|
|
|
|
SetFadeState = function(self, state)
|
|
if (state) then
|
|
self:FadeIn()
|
|
else
|
|
self:FadeOut()
|
|
end
|
|
end,
|
|
|
|
GetAllCheckboxes = function(self)
|
|
return self.allCheckBoxes
|
|
end,
|
|
|
|
GetCheckbox = function(self, checkboxId)
|
|
local allCheckboxes = self:GetAllCheckboxes()
|
|
local checkbox = allCheckboxes[checkboxId]
|
|
if (not checkbox) then
|
|
checkbox = self:CreateCheckbox()
|
|
end
|
|
return checkbox
|
|
end,
|
|
|
|
CreateCheckbox = function(self)
|
|
local checkbox = detailsFramework:CreateSwitch(self, function()end, false)
|
|
checkbox:SetTemplate(detailsFramework:GetTemplate("switch", "OPTIONS_CHECKBOX_BRIGHT_TEMPLATE"))
|
|
checkbox:SetAsCheckBox()
|
|
checkbox.Icon = detailsFramework:CreateImage(checkbox, "", 16, 16)
|
|
checkbox.Label = detailsFramework:CreateLabel(checkbox, "")
|
|
self.allCheckBoxes[#self.allCheckBoxes + 1] = checkbox
|
|
return checkbox
|
|
end,
|
|
|
|
ResetAllCheckboxes = function(self)
|
|
local radioCheckboxes = self:GetAllCheckboxes()
|
|
for i = 1, #radioCheckboxes do
|
|
local checkBox = radioCheckboxes[i]
|
|
checkBox:Hide()
|
|
end
|
|
end,
|
|
|
|
--if the list of checkboxes are a radio group
|
|
RadioOnClick = function(checkbox, fixedParam, value)
|
|
--turn off all checkboxes
|
|
---@type df_checkboxgroup
|
|
local radioGroup = checkbox:GetParent()
|
|
radioGroup:DeselectAll()
|
|
|
|
--turn on the clicked checkbox
|
|
checkbox:SetValue(true)
|
|
|
|
--callback
|
|
if (checkbox._callback) then
|
|
detailsFramework:QuickDispatch(checkbox._callback, fixedParam, checkbox._optionid)
|
|
end
|
|
end,
|
|
|
|
RefreshCheckbox = function(self, checkbox, optionTable, optionId)
|
|
checkbox = checkbox.GetCapsule and checkbox:GetCapsule() or checkbox
|
|
---@cast checkbox df_radiogroup_checkbox
|
|
|
|
local width, height = optionTable.width or 20, optionTable.height or 20
|
|
checkbox:SetSize(width, height)
|
|
|
|
local setFunc = self.options.is_radio and self.RadioOnClick or optionTable.set
|
|
checkbox:SetSwitchFunction(setFunc)
|
|
checkbox._callback = optionTable.callback
|
|
checkbox._set = self.options.is_radio and optionTable.callback or optionTable.set
|
|
checkbox._optionid = optionId
|
|
checkbox:SetFixedParameter(optionTable.param or optionId)
|
|
|
|
local isChecked = type(optionTable.get) == "function" and detailsFramework:Dispatch(optionTable.get) or false
|
|
checkbox:SetValue(isChecked)
|
|
|
|
checkbox.Label.text = optionTable.name
|
|
checkbox.Label.textsize = optionTable.text_size or self.options.text_size
|
|
checkbox.Label.textcolor = self.options.text_color
|
|
checkbox.Label.outline = self.options.text_outline
|
|
|
|
if (optionTable.texture) then
|
|
checkbox.Icon:SetTexture(optionTable.texture)
|
|
checkbox.Icon:SetSize(width, height)
|
|
checkbox.Icon:SetPoint("left", checkbox, "right", 2, 0)
|
|
checkbox.Label:SetPoint("left", checkbox.Icon, "right", 2, 0)
|
|
checkbox.tooltip = optionTable.tooltip
|
|
|
|
if (optionTable.texcoord) then
|
|
checkbox.Icon:SetTexCoord(unpack(optionTable.texcoord))
|
|
else
|
|
checkbox.Icon:SetTexCoord(0, 1, 0, 1)
|
|
end
|
|
else
|
|
checkbox.Icon:SetTexture("")
|
|
checkbox.Label:SetPoint("left", checkbox, "right", 2, 0)
|
|
end
|
|
|
|
checkbox.__width = width + (checkbox.Icon:IsShown() and (checkbox.Icon:GetWidth() + 2)) + (checkbox.Label:GetStringWidth()) + 2
|
|
checkbox.widget.__width = checkbox.__width
|
|
|
|
checkbox.__height = height + (checkbox.Icon:IsShown() and (checkbox.Icon:GetHeight() + 2))
|
|
checkbox.widget.__height = checkbox.__height
|
|
end,
|
|
|
|
Refresh = function(self)
|
|
self:ResetAllCheckboxes()
|
|
local radioOptions = self:GetOptions()
|
|
local totalWidth = 0
|
|
local maxHeight = 0
|
|
|
|
for optionId, optionsTable in ipairs(radioOptions) do
|
|
local checkbox = self:GetCheckbox(optionId)
|
|
checkbox.OptionID = optionId
|
|
checkbox:Show()
|
|
self:RefreshCheckbox(checkbox, optionsTable, optionId)
|
|
totalWidth = totalWidth + checkbox.__width
|
|
|
|
if (checkbox:GetHeight() > maxHeight) then
|
|
maxHeight = checkbox:GetHeight()
|
|
end
|
|
end
|
|
|
|
if (self.AnchorOptions.min_width) then
|
|
totalWidth = math.max(self.AnchorOptions.min_width * #radioOptions, totalWidth)
|
|
end
|
|
|
|
self:SetSize(totalWidth, maxHeight)
|
|
|
|
--sending false to automatically use the radio group children
|
|
self:ArrangeFrames(false, self.AnchorOptions)
|
|
end,
|
|
|
|
Select = function(self, option)
|
|
local allCheckBoxes = self:GetAllCheckboxes()
|
|
local thisCheckbox = allCheckBoxes[option]
|
|
if (thisCheckbox) then
|
|
local callbackFunc = thisCheckbox:GetSwitchFunction()
|
|
if (callbackFunc) then
|
|
detailsFramework.RadioGroupCoreFunctions.RadioOnClick(thisCheckbox, thisCheckbox:GetFixedParameter(), true)
|
|
end
|
|
end
|
|
end,
|
|
|
|
GetSelected = function(self)
|
|
local allCheckBoxes = self:GetAllCheckboxes()
|
|
for i = 1, #allCheckBoxes do
|
|
local thisCheckbox = allCheckBoxes[i]
|
|
if (thisCheckbox:GetValue()) then
|
|
return thisCheckbox._optionid, thisCheckbox:GetFixedParameter()
|
|
end
|
|
end
|
|
return 0
|
|
end,
|
|
|
|
SetOptions = function(self, radioOptions)
|
|
self.RadioOptionsTable = radioOptions
|
|
self:Refresh()
|
|
end,
|
|
|
|
GetOptions = function(self)
|
|
return self.RadioOptionsTable
|
|
end,
|
|
}
|
|
|
|
---@class df_radiooptions : table
|
|
---@field name string|table can be a regular string or a locTable
|
|
---@field get fun():any?
|
|
---@field set fun(self:df_radiooptions, param, value)
|
|
---@field param any?
|
|
---@field texture string?
|
|
---@field texcoord table?
|
|
---@field width number?
|
|
---@field height number?
|
|
---@field text_size number?
|
|
---@field callback fun()?
|
|
---@field backdrop table?
|
|
---@field backdrop_color table?
|
|
---@field backdrop_border_color table?
|
|
|
|
--[=[
|
|
radionOptions: an index table with options for the radio group {name = "", set = func (self, param, value), param = value, get = func, texture = "", texcoord = {}}
|
|
set function receives as self the checkbox, use :GetParent() to get the radion group frame
|
|
if get function return nil or false the checkbox isn't checked
|
|
name: the name of the frame
|
|
options: override options for default_radiogroup_options table
|
|
anchorOptions: override options for default_framelayout_options table
|
|
--]=]
|
|
|
|
---@class df_checkboxgroup : frame, df_optionsmixin, df_radiogroupmixin, df_framelayout
|
|
|
|
---@param parent frame
|
|
---@param radioOptions table
|
|
---@param name string?
|
|
---@param options table?
|
|
---@param anchorOptions table?
|
|
---@return df_checkboxgroup
|
|
function detailsFramework:CreateCheckboxGroup(parent, radioOptions, name, options, anchorOptions)
|
|
local newCheckboxGroup = CreateFrame("frame", name, parent, "BackdropTemplate")
|
|
|
|
detailsFramework:Mixin(newCheckboxGroup, detailsFramework.OptionsFunctions)
|
|
detailsFramework:Mixin(newCheckboxGroup, detailsFramework.RadioGroupCoreFunctions)
|
|
detailsFramework:Mixin(newCheckboxGroup, detailsFramework.LayoutFrame)
|
|
|
|
newCheckboxGroup.allCheckBoxes = {}
|
|
|
|
newCheckboxGroup:BuildOptionsTable(default_radiogroup_options, options)
|
|
|
|
newCheckboxGroup:SetBackdrop(newCheckboxGroup.options.backdrop)
|
|
newCheckboxGroup:SetBackdropColor(unpack(newCheckboxGroup.options.backdrop_color))
|
|
newCheckboxGroup:SetBackdropBorderColor(unpack(newCheckboxGroup.options.backdrop_border_color))
|
|
|
|
newCheckboxGroup.AnchorOptions = anchorOptions or {}
|
|
|
|
if (newCheckboxGroup.options.title) then
|
|
local titleLabel = detailsFramework:CreateLabel(newCheckboxGroup, newCheckboxGroup.options.title, detailsFramework:GetTemplate("font", "ORANGE_FONT_TEMPLATE"))
|
|
titleLabel:SetPoint("bottomleft", newCheckboxGroup, "topleft", 0, 2)
|
|
newCheckboxGroup.Title = titleLabel
|
|
end
|
|
|
|
newCheckboxGroup:SetOptions(radioOptions)
|
|
|
|
return newCheckboxGroup
|
|
end
|
|
|
|
function detailsFramework:CreateRadionGroup(parent, radioOptions, name, options, anchorOptions) --alias for miss spelled old function
|
|
return detailsFramework:CreateRadioGroup(parent, radioOptions, name, options, anchorOptions)
|
|
end
|
|
|
|
---@class df_radiogroup : frame, df_optionsmixin, df_radiogroupmixin, df_framelayout
|
|
|
|
function detailsFramework:CreateRadioGroup(parent, radioOptions, name, options, anchorOptions)
|
|
options = options or {}
|
|
options.is_radio = true
|
|
return detailsFramework:CreateCheckboxGroup(parent, radioOptions, name, options, anchorOptions)
|
|
end
|
|
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--simple data scroll
|
|
|
|
detailsFramework.DataScrollFunctions = {
|
|
RefreshScroll = function(self, data, offset, totalLines)
|
|
local filter = self.Filter
|
|
local currentData = {}
|
|
if (type(filter) == "string" and filter ~= "") then
|
|
for i = 1, #data do
|
|
for o = 1, #data[i] do
|
|
if (data[i][o]:find(filter)) then
|
|
table.insert(currentData, data[i])
|
|
break
|
|
end
|
|
end
|
|
end
|
|
else
|
|
currentData = data
|
|
end
|
|
|
|
if (self.SortAlphabetical) then
|
|
table.sort (currentData, function(t1, t2) return t1[1] < t2[1] end)
|
|
end
|
|
|
|
--update the scroll
|
|
for i = 1, totalLines do
|
|
local index = i + offset
|
|
local thisData = currentData [index]
|
|
if (thisData) then
|
|
local line = self:GetLine (i)
|
|
line:Update (index, thisData)
|
|
end
|
|
end
|
|
end,
|
|
|
|
CreateLine = function(self, index)
|
|
--create a new line
|
|
local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate")
|
|
line.Update = self.options.update_line_func
|
|
|
|
--set its parameters
|
|
line:SetPoint("topleft", self, "topleft", 1, -((index-1) * (self.options.line_height+1)) - 1)
|
|
line:SetSize(self.options.width - 2, self.options.line_height)
|
|
line:RegisterForClicks ("LeftButtonDown", "RightButtonDown")
|
|
|
|
line:SetScript("OnEnter", self.options.on_enter)
|
|
line:SetScript("OnLeave", self.options.on_leave)
|
|
line:SetScript("OnClick", self.options.on_click)
|
|
|
|
line:SetBackdrop(self.options.backdrop)
|
|
line:SetBackdropColor(unpack(self.options.backdrop_color))
|
|
line:SetBackdropBorderColor(unpack(self.options.backdrop_border_color))
|
|
|
|
local title = detailsFramework:CreateLabel(line, "", detailsFramework:GetTemplate("font", self.options.title_template))
|
|
local date = detailsFramework:CreateLabel(line, "", detailsFramework:GetTemplate("font", self.options.title_template))
|
|
local text = detailsFramework:CreateLabel(line, "", detailsFramework:GetTemplate("font", self.options.text_tempate))
|
|
|
|
title.textsize = 14
|
|
date.textsize = 14
|
|
text:SetSize(self.options.width - 20, self.options.line_height)
|
|
text:SetJustifyV ("top")
|
|
|
|
--setup anchors
|
|
if (self.options.show_title) then
|
|
title:SetPoint("topleft", line, "topleft", 2, 0)
|
|
date:SetPoint("topright", line, "topright", -2, 0)
|
|
text:SetPoint("topleft", title, "bottomleft", 0, -4)
|
|
else
|
|
text:SetPoint("topleft", line, "topleft", 2, 0)
|
|
end
|
|
|
|
line.Title = title
|
|
line.Date = date
|
|
line.Text = text
|
|
|
|
line.backdrop_color = self.options.backdrop_color or {.1, .1, .1, .3}
|
|
line.backdrop_color_highlight = self.options.backdrop_color_highlight or {.3, .3, .3, .5}
|
|
|
|
return line
|
|
end,
|
|
|
|
LineOnEnter = function(self)
|
|
self:SetBackdropColor(unpack(self.backdrop_color_highlight))
|
|
end,
|
|
LineOnLeave = function(self)
|
|
self:SetBackdropColor(unpack(self.backdrop_color))
|
|
end,
|
|
|
|
OnClick = function(self)
|
|
|
|
end,
|
|
|
|
UpdateLine = function(line, lineIndex, data)
|
|
local parent = line:GetParent()
|
|
|
|
if (parent.options.show_title) then
|
|
line.Title.text = data [2] or ""
|
|
line.Date.text = data [3] or ""
|
|
line.Text.text = data [4] or ""
|
|
else
|
|
line.Text.text = data [2] or ""
|
|
end
|
|
|
|
if (line:GetParent().OnUpdateLineHook) then
|
|
detailsFramework:CoreDispatch((line:GetName() or "ScrollBoxDataScrollUpdateLineHook") .. ":UpdateLineHook()", line:GetParent().OnUpdateLineHook, line, lineIndex, data)
|
|
end
|
|
end,
|
|
}
|
|
|
|
local default_datascroll_options = {
|
|
width = 400,
|
|
height = 700,
|
|
line_amount = 10,
|
|
line_height = 20,
|
|
|
|
show_title = true,
|
|
|
|
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
backdrop_color = {0, 0, 0, 0.2},
|
|
backdrop_color_highlight = {.2, .2, .2, 0.4},
|
|
backdrop_border_color = {0.1, 0.1, 0.1, .2},
|
|
|
|
title_template = "ORANGE_FONT_TEMPLATE",
|
|
text_tempate = "OPTIONS_FONT_TEMPLATE",
|
|
|
|
create_line_func = detailsFramework.DataScrollFunctions.CreateLine,
|
|
update_line_func = detailsFramework.DataScrollFunctions.UpdateLine,
|
|
refresh_func = detailsFramework.DataScrollFunctions.RefreshScroll,
|
|
on_enter = detailsFramework.DataScrollFunctions.LineOnEnter,
|
|
on_leave = detailsFramework.DataScrollFunctions.LineOnLeave,
|
|
on_click = detailsFramework.DataScrollFunctions.OnClick,
|
|
|
|
data = {},
|
|
}
|
|
|
|
--[=[
|
|
Create a scroll frame to show text in an organized way
|
|
Functions in the options table can be overritten to customize the layout
|
|
@parent = the parent of the frame
|
|
@name = the frame name to use in the CreateFrame call
|
|
@options = options table to override default values from the table above
|
|
--]=]
|
|
function detailsFramework:CreateDataScrollFrame (parent, name, options)
|
|
--call the mixin with a dummy table to built the default options before the frame creation
|
|
--this is done because CreateScrollBox needs parameters at creation time
|
|
local optionsTable = {}
|
|
detailsFramework.OptionsFunctions.BuildOptionsTable (optionsTable, default_datascroll_options, options)
|
|
optionsTable = optionsTable.options
|
|
|
|
--scroll frame
|
|
local newScroll = detailsFramework:CreateScrollBox (parent, name, optionsTable.refresh_func, optionsTable.data, optionsTable.width, optionsTable.height, optionsTable.line_amount, optionsTable.line_height)
|
|
detailsFramework:ReskinSlider(newScroll)
|
|
|
|
detailsFramework:Mixin(newScroll, detailsFramework.OptionsFunctions)
|
|
detailsFramework:Mixin(newScroll, detailsFramework.LayoutFrame)
|
|
|
|
newScroll:BuildOptionsTable (default_datascroll_options, options)
|
|
|
|
--create the scrollbox lines
|
|
for i = 1, newScroll.options.line_amount do
|
|
newScroll:CreateLine (newScroll.options.create_line_func)
|
|
end
|
|
|
|
newScroll:Refresh()
|
|
|
|
return newScroll
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--"WHAT's NEW" window
|
|
|
|
local default_newsframe_options = {
|
|
width = 400,
|
|
height = 700,
|
|
|
|
line_amount = 16,
|
|
line_height = 40,
|
|
|
|
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
backdrop_color = {0, 0, 0, 0.2},
|
|
backdrop_border_color = {0.1, 0.1, 0.1, .2},
|
|
|
|
title = "What's New?",
|
|
show_title = true,
|
|
}
|
|
|
|
detailsFramework.NewsFrameFunctions = {
|
|
|
|
}
|
|
|
|
--[=[
|
|
Get the amount of news that the player didn't see yet
|
|
@newsTable = an indexed table of tables
|
|
@lastNewsTime = last time the player opened the news window
|
|
--]=]
|
|
function detailsFramework:GetNumNews (newsTable, lastNewsTime)
|
|
local now = time()
|
|
local nonReadNews = 0
|
|
|
|
for _, news in ipairs(newsTable) do
|
|
if (news[1] > lastNewsTime) then
|
|
nonReadNews = nonReadNews + 1
|
|
end
|
|
end
|
|
|
|
return nonReadNews
|
|
end
|
|
|
|
--[=[
|
|
Creates a panel with a scroll to show texts organized in separated lines
|
|
@parent = the parent of the frame
|
|
@name = the frame name to use in the CreateFrame call
|
|
@options = options table to override default values from the table above
|
|
@newsTable = an indexed table of tables
|
|
@db = (optional) an empty table from the addon database to store the position of the frame between game sessions
|
|
--]=]
|
|
function detailsFramework:CreateNewsFrame (parent, name, options, newsTable, db)
|
|
|
|
local f = detailsFramework:CreateSimplePanel(parent, 400, 700, options and options.title or default_newsframe_options.title, name, {UseScaleBar = db and true}, db)
|
|
f:SetFrameStrata("MEDIUM")
|
|
detailsFramework:ApplyStandardBackdrop(f)
|
|
|
|
detailsFramework:Mixin(f, detailsFramework.OptionsFunctions)
|
|
detailsFramework:Mixin(f, detailsFramework.LayoutFrame)
|
|
|
|
f:BuildOptionsTable (default_newsframe_options, options)
|
|
|
|
f:SetSize(f.options.width, f.options.height)
|
|
f:SetBackdrop(f.options.backdrop)
|
|
f:SetBackdropColor(unpack(f.options.backdrop_color))
|
|
f:SetBackdropBorderColor(unpack(f.options.backdrop_border_color))
|
|
|
|
local scrollOptions = {
|
|
data = newsTable,
|
|
width = f.options.width - 32, --frame distance from walls and scroll bar space
|
|
height = f.options.height - 40 + (not f.options.show_title and 20 or 0),
|
|
line_amount = f.options.line_amount,
|
|
line_height = f.options.line_height,
|
|
}
|
|
local newsScroll = detailsFramework:CreateDataScrollFrame (f, "$parentScroll", scrollOptions)
|
|
|
|
if (not f.options.show_title) then
|
|
f.TitleBar:Hide()
|
|
newsScroll:SetPoint("topleft", f, "topleft", 5, -10)
|
|
else
|
|
newsScroll:SetPoint("topleft", f, "topleft", 5, -30)
|
|
end
|
|
|
|
f.NewsScroll = newsScroll
|
|
|
|
return f
|
|
end
|
|
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--statusbar info
|
|
|
|
--[[
|
|
authorTable = {
|
|
{
|
|
authorName = "author name 1",
|
|
link = "twitter.com/author1Handle",
|
|
}
|
|
}
|
|
]]
|
|
|
|
function detailsFramework:BuildStatusbarAuthorInfo(f, addonBy, authorsNameString)
|
|
local authorName = detailsFramework:CreateLabel(f, "" .. (addonBy or "An addon by ") .. "|cFFFFFFFF" .. (authorsNameString or "Terciob") .. "|r")
|
|
authorName.textcolor = "silver"
|
|
local discordLabel = detailsFramework:CreateLabel(f, "Discord: ")
|
|
discordLabel.textcolor = "silver"
|
|
|
|
local options_dropdown_template = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")
|
|
local discordTextEntry = detailsFramework:CreateTextEntry(f, function()end, 200, 18, "DiscordTextBox", _, _, options_dropdown_template)
|
|
discordTextEntry:SetText("https://discord.gg/AGSzAZX")
|
|
discordTextEntry:SetFrameLevel(5000)
|
|
|
|
authorName:SetPoint("left", f, "left", 2, 0)
|
|
discordLabel:SetPoint("left", authorName, "right", 20, 0)
|
|
discordTextEntry:SetPoint("left", discordLabel, "right", 2, 0)
|
|
|
|
--format
|
|
authorName:SetAlpha(.6)
|
|
discordLabel:SetAlpha(.6)
|
|
discordTextEntry:SetAlpha(.6)
|
|
discordTextEntry:SetBackdropBorderColor(1, 1, 1, 0)
|
|
|
|
discordTextEntry:SetHook("OnEditFocusGained", function()
|
|
discordTextEntry:HighlightText()
|
|
end)
|
|
|
|
f.authorName = authorName
|
|
f.discordLabel = discordLabel
|
|
f.discordTextEntry = discordTextEntry
|
|
end
|
|
|
|
local statusbar_default_options = {
|
|
attach = "bottom", --bottomleft from statusbar attach to bottomleft of the frame | other option is "top": topleft attach to bottomleft
|
|
}
|
|
|
|
function detailsFramework:CreateStatusBar(f, options)
|
|
local statusBar = CreateFrame("frame", nil, f, "BackdropTemplate")
|
|
|
|
detailsFramework:Mixin(statusBar, detailsFramework.OptionsFunctions)
|
|
detailsFramework:Mixin(statusBar, detailsFramework.LayoutFrame)
|
|
|
|
statusBar:BuildOptionsTable (statusbar_default_options, options)
|
|
|
|
if (statusBar.options.attach == "bottom") then
|
|
statusBar:SetPoint("bottomleft", f, "bottomleft")
|
|
statusBar:SetPoint("bottomright", f, "bottomright")
|
|
|
|
else
|
|
statusBar:SetPoint("topleft", f, "bottomleft")
|
|
statusBar:SetPoint("topright", f, "bottomright")
|
|
end
|
|
|
|
statusBar:SetHeight(20)
|
|
detailsFramework:ApplyStandardBackdrop(statusBar)
|
|
statusBar:SetAlpha(0.8)
|
|
|
|
return statusBar
|
|
end
|
|
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--border frame
|
|
|
|
--[=[
|
|
DF:CreateBorderFrame (parent, name)
|
|
creates a frame with 4 child textures attached to each one of the 4 sides of a frame
|
|
@parent = parent frame to pass to CreateFrame function
|
|
@name = name of the frame, if omitted a random name is created
|
|
--]=]
|
|
|
|
detailsFramework.BorderFunctions = {
|
|
SetBorderColor = function(self, r, g, b, a)
|
|
r, g, b, a = detailsFramework:ParseColors(r, g, b, a)
|
|
for _, texture in ipairs(self.allTextures) do
|
|
texture:SetVertexColor(r, g, b, a)
|
|
end
|
|
end,
|
|
|
|
SetBorderThickness = function(self, newThickness)
|
|
PixelUtil.SetWidth (self.leftBorder, newThickness, newThickness)
|
|
PixelUtil.SetWidth (self.rightBorder, newThickness, newThickness)
|
|
PixelUtil.SetHeight(self.topBorder, newThickness, newThickness)
|
|
PixelUtil.SetHeight(self.bottomBorder, newThickness, newThickness)
|
|
end,
|
|
|
|
WidgetType = "border",
|
|
}
|
|
|
|
-- ~borderframe
|
|
function detailsFramework:CreateBorderFrame(parent, name)
|
|
local parentName = name or ("DetailsFrameworkBorderFrame" .. tostring(math.random(1, 100000000)))
|
|
|
|
local f = CreateFrame("frame", parentName, parent, "BackdropTemplate")
|
|
f:SetFrameLevel(f:GetFrameLevel()+1)
|
|
f:SetAllPoints()
|
|
|
|
detailsFramework:Mixin(f, detailsFramework.BorderFunctions)
|
|
|
|
f.allTextures = {}
|
|
|
|
--create left border
|
|
local leftBorder = f:CreateTexture(nil, "overlay")
|
|
leftBorder:SetDrawLayer("overlay", 7)
|
|
leftBorder:SetColorTexture(1, 1, 1, 1)
|
|
table.insert(f.allTextures, leftBorder)
|
|
f.leftBorder = leftBorder
|
|
PixelUtil.SetPoint(leftBorder, "topright", f, "topleft", 0, 1, 0, 1)
|
|
PixelUtil.SetPoint(leftBorder, "bottomright", f, "bottomleft", 0, -1, 0, -1)
|
|
PixelUtil.SetWidth (leftBorder, 1, 1)
|
|
|
|
--create right border
|
|
local rightBorder = f:CreateTexture(nil, "overlay")
|
|
rightBorder:SetDrawLayer("overlay", 7)
|
|
rightBorder:SetColorTexture(1, 1, 1, 1)
|
|
table.insert(f.allTextures, rightBorder)
|
|
f.rightBorder = rightBorder
|
|
PixelUtil.SetPoint(rightBorder, "topleft", f, "topright", 0, 1, 0, 1)
|
|
PixelUtil.SetPoint(rightBorder, "bottomleft", f, "bottomright", 0, -1, 0, -1)
|
|
PixelUtil.SetWidth (rightBorder, 1, 1)
|
|
|
|
--create top border
|
|
local topBorder = f:CreateTexture(nil, "overlay")
|
|
topBorder:SetDrawLayer("overlay", 7)
|
|
topBorder:SetColorTexture(1, 1, 1, 1)
|
|
table.insert(f.allTextures, topBorder)
|
|
f.topBorder = topBorder
|
|
PixelUtil.SetPoint(topBorder, "bottomleft", f, "topleft", 0, 0, 0, 0)
|
|
PixelUtil.SetPoint(topBorder, "bottomright", f, "topright", 0, 0, 0, 0)
|
|
PixelUtil.SetHeight(topBorder, 1, 1)
|
|
|
|
--create border
|
|
local bottomBorder = f:CreateTexture(nil, "overlay")
|
|
bottomBorder:SetDrawLayer("overlay", 7)
|
|
bottomBorder:SetColorTexture(1, 1, 1, 1)
|
|
table.insert(f.allTextures, bottomBorder)
|
|
f.bottomBorder = bottomBorder
|
|
PixelUtil.SetPoint(bottomBorder, "topleft", f, "bottomleft", 0, 0, 0, 0)
|
|
PixelUtil.SetPoint(bottomBorder, "topright", f, "bottomright", 0, 0, 0, 0)
|
|
PixelUtil.SetHeight(bottomBorder, 1, 1)
|
|
|
|
return f
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--horizontal scroll frame
|
|
|
|
local timeline_options = {
|
|
width = 400,
|
|
height = 700,
|
|
line_height = 20,
|
|
line_padding = 1,
|
|
|
|
show_elapsed_timeline = true,
|
|
elapsed_timeline_height = 20,
|
|
|
|
--space to put the player/spell name and icons
|
|
header_width = 150,
|
|
|
|
--how many pixels will be use to represent 1 second
|
|
pixels_per_second = 20,
|
|
|
|
scale_min = 0.15,
|
|
scale_max = 1,
|
|
|
|
backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
backdrop_color = {0, 0, 0, 0.2},
|
|
backdrop_color_highlight = {.2, .2, .2, 0.4},
|
|
backdrop_border_color = {0.1, 0.1, 0.1, .2},
|
|
|
|
slider_backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
slider_backdrop_color = {0, 0, 0, 0.2},
|
|
slider_backdrop_border_color = {0.1, 0.1, 0.1, .2},
|
|
|
|
title_template = "ORANGE_FONT_TEMPLATE",
|
|
text_tempate = "OPTIONS_FONT_TEMPLATE",
|
|
|
|
on_enter = function(self)
|
|
self:SetBackdropColor(unpack(self.backdrop_color_highlight))
|
|
end,
|
|
on_leave = function(self)
|
|
self:SetBackdropColor(unpack(self.backdrop_color))
|
|
end,
|
|
|
|
block_on_enter = function(self)
|
|
|
|
end,
|
|
block_on_leave = function(self)
|
|
|
|
end,
|
|
}
|
|
|
|
local elapsedtime_frame_options = {
|
|
backdrop = {bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
backdrop_color = {.3, .3, .3, .7},
|
|
|
|
text_color = {1, 1, 1, 1},
|
|
text_size = 12,
|
|
text_font = "Arial Narrow",
|
|
text_outline = "NONE",
|
|
|
|
height = 20,
|
|
|
|
distance = 200, --distance in pixels between each label informing the time
|
|
distance_min = 50, --minimum distance in pixels
|
|
draw_line = true, --if true it'll draw a vertical line to represent a segment
|
|
draw_line_color = {1, 1, 1, 0.2},
|
|
draw_line_thickness = 1,
|
|
}
|
|
|
|
detailsFramework.TimeLineElapsedTimeFunctions = {
|
|
--get a label and update its appearance
|
|
GetLabel = function(self, index)
|
|
local label = self.labels [index]
|
|
|
|
if (not label) then
|
|
label = self:CreateFontString(nil, "artwork", "GameFontNormal")
|
|
label.line = self:CreateTexture(nil, "artwork")
|
|
label.line:SetColorTexture(1, 1, 1)
|
|
label.line:SetPoint("topleft", label, "bottomleft", 0, -2)
|
|
self.labels [index] = label
|
|
end
|
|
|
|
detailsFramework:SetFontColor(label, self.options.text_color)
|
|
detailsFramework:SetFontSize(label, self.options.text_size)
|
|
detailsFramework:SetFontFace (label, self.options.text_font)
|
|
detailsFramework:SetFontOutline (label, self.options.text_outline)
|
|
|
|
if (self.options.draw_line) then
|
|
label.line:SetVertexColor(unpack(self.options.draw_line_color))
|
|
label.line:SetWidth(self.options.draw_line_thickness)
|
|
label.line:Show()
|
|
else
|
|
label.line:Hide()
|
|
end
|
|
|
|
return label
|
|
end,
|
|
|
|
Reset = function(self)
|
|
for i = 1, #self.labels do
|
|
self.labels [i]:Hide()
|
|
end
|
|
end,
|
|
|
|
Refresh = function(self, elapsedTime, scale)
|
|
local parent = self:GetParent()
|
|
|
|
self:SetHeight(self.options.height)
|
|
local effectiveArea = self:GetWidth() --already scaled down width
|
|
local pixelPerSecond = elapsedTime / effectiveArea --how much 1 pixels correlate to time
|
|
|
|
local distance = self.options.distance --pixels between each segment
|
|
local minDistance = self.options.distance_min --min pixels between each segment
|
|
|
|
--scale the distance between each label showing the time with the parent's scale
|
|
distance = distance * scale
|
|
distance = max(distance, minDistance)
|
|
|
|
local amountSegments = ceil (effectiveArea / distance)
|
|
|
|
for i = 1, amountSegments do
|
|
local label = self:GetLabel (i)
|
|
local xOffset = distance * (i - 1)
|
|
label:SetPoint("left", self, "left", xOffset, 0)
|
|
|
|
local secondsOfTime = pixelPerSecond * xOffset
|
|
|
|
label:SetText(detailsFramework:IntegerToTimer(floor(secondsOfTime)))
|
|
|
|
if (label.line:IsShown()) then
|
|
label.line:SetHeight(parent:GetParent():GetHeight())
|
|
end
|
|
|
|
label:Show()
|
|
end
|
|
end,
|
|
}
|
|
|
|
--creates a frame to show the elapsed time in a row
|
|
function detailsFramework:CreateElapsedTimeFrame(parent, name, options)
|
|
local elapsedTimeFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
|
|
|
detailsFramework:Mixin(elapsedTimeFrame, detailsFramework.OptionsFunctions)
|
|
detailsFramework:Mixin(elapsedTimeFrame, detailsFramework.LayoutFrame)
|
|
detailsFramework:Mixin(elapsedTimeFrame, detailsFramework.TimeLineElapsedTimeFunctions)
|
|
|
|
elapsedTimeFrame:BuildOptionsTable(elapsedtime_frame_options, options)
|
|
|
|
elapsedTimeFrame:SetBackdrop(elapsedTimeFrame.options.backdrop)
|
|
elapsedTimeFrame:SetBackdropColor(unpack(elapsedTimeFrame.options.backdrop_color))
|
|
|
|
elapsedTimeFrame.labels = {}
|
|
|
|
return elapsedTimeFrame
|
|
end
|
|
|
|
|
|
detailsFramework.TimeLineBlockFunctions = {
|
|
--self is the line
|
|
SetBlock = function(self, index, blockInfo)
|
|
--get the block information
|
|
--see what is the current scale
|
|
--adjust the block position
|
|
|
|
local block = self:GetBlock (index)
|
|
|
|
--need:
|
|
--the total time of the timeline
|
|
--the current scale of the timeline
|
|
--the elapsed time of this block
|
|
--icon of the block
|
|
--text
|
|
--background color
|
|
|
|
end,
|
|
|
|
SetBlocksFromData = function(self)
|
|
local parent = self:GetParent():GetParent()
|
|
local data = parent.data
|
|
local defaultColor = parent.defaultColor --guarantee to have a value
|
|
|
|
self:Show()
|
|
|
|
--none of these values are scaled, need to calculate
|
|
local pixelPerSecond = parent.pixelPerSecond
|
|
local totalLength = parent.totalLength
|
|
local scale = parent.currentScale
|
|
|
|
pixelPerSecond = pixelPerSecond * scale
|
|
|
|
local headerWidth = parent.headerWidth
|
|
|
|
--dataIndex stores which line index from the data this line will use
|
|
--lineData store members: .text .icon .timeline
|
|
local lineData = data.lines[self.dataIndex]
|
|
|
|
self.spellId = lineData.spellId
|
|
|
|
--if there's an icon, anchor the text at the right side of the icon
|
|
--this is the title and icon of the title
|
|
if (lineData.icon) then
|
|
self.icon:SetTexture(lineData.icon)
|
|
if (lineData.coords) then
|
|
self.icon:SetTexCoord(unpack(lineData.coords))
|
|
else
|
|
self.icon:SetTexCoord(.1, .9, .1, .9)
|
|
end
|
|
self.text:SetText(lineData.text or "")
|
|
self.text:SetPoint("left", self.icon.widget, "right", 2, 0)
|
|
else
|
|
self.icon:SetTexture(nil)
|
|
self.text:SetText(lineData.text or "")
|
|
self.text:SetPoint("left", self, "left", 2, 0)
|
|
end
|
|
|
|
if (self.dataIndex % 2 == 1) then
|
|
self:SetBackdropColor(0, 0, 0, 0)
|
|
else
|
|
local r, g, b, a = unpack(self.backdrop_color)
|
|
self:SetBackdropColor(r, g, b, a)
|
|
end
|
|
|
|
self:SetWidth(5000)
|
|
|
|
local timelineData = lineData.timeline
|
|
local spellId = lineData.spellId
|
|
local useIconOnBlock = data.useIconOnBlocks
|
|
|
|
local baseFrameLevel = parent:GetFrameLevel() + 10
|
|
|
|
for i = 1, #timelineData do
|
|
local blockInfo = timelineData[i]
|
|
|
|
local timeInSeconds = blockInfo[1]
|
|
local length = blockInfo[2]
|
|
local isAura = blockInfo[3]
|
|
local auraDuration = blockInfo[4]
|
|
local blockSpellId = blockInfo[5]
|
|
|
|
local payload = blockInfo.payload
|
|
|
|
local xOffset = pixelPerSecond * timeInSeconds
|
|
local width = pixelPerSecond * length
|
|
|
|
if (timeInSeconds < -0.2) then
|
|
xOffset = xOffset / 2.5
|
|
end
|
|
|
|
local block = self:GetBlock(i)
|
|
block:Show()
|
|
block:SetFrameLevel(baseFrameLevel + i)
|
|
|
|
PixelUtil.SetPoint(block, "left", self, "left", xOffset + headerWidth, 0)
|
|
|
|
block.info.spellId = blockSpellId or spellId
|
|
block.info.time = timeInSeconds
|
|
block.info.duration = auraDuration
|
|
block.info.payload = payload
|
|
|
|
if (useIconOnBlock) then
|
|
local iconTexture = lineData.icon
|
|
if (blockSpellId) then
|
|
iconTexture = GetSpellTexture(blockSpellId)
|
|
end
|
|
|
|
block.icon:SetTexture(iconTexture)
|
|
block.icon:SetTexCoord(.1, .9, .1, .9)
|
|
block.icon:SetAlpha(.834)
|
|
block.icon:SetSize(self:GetHeight(), self:GetHeight())
|
|
|
|
if (timeInSeconds < -0.2) then
|
|
block.icon:SetDesaturated(true)
|
|
else
|
|
block.icon:SetDesaturated(false)
|
|
end
|
|
|
|
PixelUtil.SetSize(block, self:GetHeight(), self:GetHeight())
|
|
|
|
if (isAura) then
|
|
block.auraLength:Show()
|
|
block.auraLength:SetWidth(pixelPerSecond * isAura)
|
|
block:SetWidth(max(pixelPerSecond * isAura, 16))
|
|
else
|
|
block.auraLength:Hide()
|
|
end
|
|
|
|
block.background:SetVertexColor(0, 0, 0, 0)
|
|
else
|
|
block.background:SetVertexColor(0, 0, 0, 0)
|
|
PixelUtil.SetSize(block, max(width, 16), self:GetHeight())
|
|
block.auraLength:Hide()
|
|
end
|
|
end
|
|
end,
|
|
|
|
GetBlock = function(self, index)
|
|
local block = self.blocks [index]
|
|
if (not block) then
|
|
block = CreateFrame("frame", nil, self, "BackdropTemplate")
|
|
self.blocks [index] = block
|
|
|
|
local background = block:CreateTexture(nil, "background")
|
|
background:SetColorTexture(1, 1, 1, 1)
|
|
local icon = block:CreateTexture(nil, "artwork")
|
|
local text = block:CreateFontString(nil, "artwork")
|
|
local auraLength = block:CreateTexture(nil, "border")
|
|
|
|
background:SetAllPoints()
|
|
icon:SetPoint("left")
|
|
text:SetPoint("left", icon, "left", 2, 0)
|
|
auraLength:SetPoint("topleft", icon, "topleft", 0, 0)
|
|
auraLength:SetPoint("bottomleft", icon, "bottomleft", 0, 0)
|
|
auraLength:SetColorTexture(1, 1, 1, 1)
|
|
auraLength:SetVertexColor(1, 1, 1, 0.1)
|
|
|
|
block.icon = icon
|
|
block.text = text
|
|
block.background = background
|
|
block.auraLength = auraLength
|
|
|
|
block:SetScript("OnEnter", self:GetParent():GetParent().options.block_on_enter)
|
|
block:SetScript("OnLeave", self:GetParent():GetParent().options.block_on_leave)
|
|
|
|
block:SetMouseClickEnabled(false)
|
|
block.info = {}
|
|
end
|
|
|
|
return block
|
|
end,
|
|
|
|
Reset = function(self)
|
|
--attention, it doesn't reset icon texture, text and background color
|
|
for i = 1, #self.blocks do
|
|
self.blocks [i]:Hide()
|
|
end
|
|
self:Hide()
|
|
end,
|
|
}
|
|
|
|
detailsFramework.TimeLineFunctions = {
|
|
GetLine = function(self, index)
|
|
local line = self.lines [index]
|
|
if (not line) then
|
|
--create a new line
|
|
line = CreateFrame("frame", "$parentLine" .. index, self.body, "BackdropTemplate")
|
|
detailsFramework:Mixin(line, detailsFramework.TimeLineBlockFunctions)
|
|
self.lines [index] = line
|
|
|
|
local lineHeader = CreateFrame("frame", nil, line, "BackdropTemplate")
|
|
lineHeader:SetPoint("topleft", line, "topleft", 0, 0)
|
|
lineHeader:SetPoint("bottomleft", line, "bottomleft", 0, 0)
|
|
lineHeader:SetScript("OnEnter", self.options.header_on_enter)
|
|
lineHeader:SetScript("OnLeave", self.options.header_on_leave)
|
|
|
|
line.lineHeader = lineHeader
|
|
|
|
--store the individual textures that shows the timeline information
|
|
line.blocks = {}
|
|
line.SetBlock = detailsFramework.TimeLineBlockFunctions.SetBlock
|
|
line.GetBlock = detailsFramework.TimeLineBlockFunctions.GetBlock
|
|
|
|
--set its parameters
|
|
|
|
if (self.options.show_elapsed_timeline) then
|
|
line:SetPoint("topleft", self.body, "topleft", 1, -((index-1) * (self.options.line_height + 1)) - 2 - self.options.elapsed_timeline_height)
|
|
else
|
|
line:SetPoint("topleft", self.body, "topleft", 1, -((index-1) * (self.options.line_height + 1)) - 1)
|
|
end
|
|
line:SetSize(1, self.options.line_height) --width is set when updating the frame
|
|
|
|
line:SetScript("OnEnter", self.options.on_enter)
|
|
line:SetScript("OnLeave", self.options.on_leave)
|
|
line:SetMouseClickEnabled(false)
|
|
|
|
line:SetBackdrop(self.options.backdrop)
|
|
line:SetBackdropColor(unpack(self.options.backdrop_color))
|
|
line:SetBackdropBorderColor(unpack(self.options.backdrop_border_color))
|
|
|
|
local icon = detailsFramework:CreateImage(line, "", self.options.line_height, self.options.line_height)
|
|
icon:SetPoint("left", line, "left", 2, 0)
|
|
line.icon = icon
|
|
|
|
local text = detailsFramework:CreateLabel(line, "", detailsFramework:GetTemplate("font", self.options.title_template))
|
|
text:SetPoint("left", icon.widget, "right", 2, 0)
|
|
line.text = text
|
|
|
|
line.backdrop_color = self.options.backdrop_color or {.1, .1, .1, .3}
|
|
line.backdrop_color_highlight = self.options.backdrop_color_highlight or {.3, .3, .3, .5}
|
|
end
|
|
|
|
return line
|
|
end,
|
|
|
|
ResetAllLines = function(self)
|
|
for i = 1, #self.lines do
|
|
self.lines[i]:Reset()
|
|
end
|
|
end,
|
|
|
|
AdjustScale = function(self, index)
|
|
|
|
end,
|
|
|
|
--todo
|
|
--make the on enter and leave tooltips
|
|
--set icons and texts
|
|
--skin the sliders
|
|
|
|
RefreshTimeLine = function(self)
|
|
--debug
|
|
--self.currentScale = 1
|
|
|
|
--calculate the total width
|
|
local pixelPerSecond = self.options.pixels_per_second
|
|
local totalLength = self.data.length or 1
|
|
local currentScale = self.currentScale
|
|
|
|
self.scaleSlider:Enable()
|
|
|
|
--how many pixels represent 1 second
|
|
local bodyWidth = totalLength * pixelPerSecond * currentScale
|
|
self.body:SetWidth(bodyWidth + self.options.header_width)
|
|
self.body.effectiveWidth = bodyWidth
|
|
|
|
--reduce the default canvas size from the body with and don't allow the max value be negative
|
|
local newMaxValue = max(bodyWidth - (self:GetWidth() - self.options.header_width), 0)
|
|
|
|
--adjust the scale slider range
|
|
local oldMin, oldMax = self.horizontalSlider:GetMinMaxValues()
|
|
self.horizontalSlider:SetMinMaxValues(0, newMaxValue)
|
|
self.horizontalSlider:SetValue(detailsFramework:MapRangeClamped(oldMin, oldMax, 0, newMaxValue, self.horizontalSlider:GetValue()))
|
|
|
|
local defaultColor = self.data.defaultColor or {1, 1, 1, 1}
|
|
|
|
--cache values
|
|
self.pixelPerSecond = pixelPerSecond
|
|
self.totalLength = totalLength
|
|
self.defaultColor = defaultColor
|
|
self.headerWidth = self.options.header_width
|
|
|
|
--calculate the total height
|
|
local lineHeight = self.options.line_height
|
|
local linePadding = self.options.line_padding
|
|
|
|
local bodyHeight = (lineHeight + linePadding) * #self.data.lines
|
|
self.body:SetHeight(bodyHeight)
|
|
self.verticalSlider:SetMinMaxValues(0, max(bodyHeight - self:GetHeight(), 0))
|
|
self.verticalSlider:SetValue(0)
|
|
|
|
--refresh lines
|
|
self:ResetAllLines()
|
|
for i = 1, #self.data.lines do
|
|
local line = self:GetLine(i)
|
|
line.dataIndex = i --this index is used inside the line update function to know which data to get
|
|
line.lineHeader:SetWidth(self.options.header_width)
|
|
line:SetBlocksFromData() --the function to update runs within the line object
|
|
end
|
|
|
|
--refresh elapsed time frame
|
|
--the elapsed frame must have a width before the refresh function is called
|
|
self.elapsedTimeFrame:ClearAllPoints()
|
|
self.elapsedTimeFrame:SetPoint("topleft", self.body, "topleft", self.options.header_width, 0)
|
|
self.elapsedTimeFrame:SetPoint("topright", self.body, "topright", 0, 0)
|
|
self.elapsedTimeFrame:Reset()
|
|
|
|
self.elapsedTimeFrame:Refresh(self.data.length, self.currentScale)
|
|
end,
|
|
|
|
SetData = function(self, data)
|
|
self.data = data
|
|
self:RefreshTimeLine()
|
|
end,
|
|
}
|
|
|
|
--creates a regular scroll in horizontal position
|
|
function detailsFramework:CreateTimeLineFrame(parent, name, options, timelineOptions)
|
|
local width = options and options.width or timeline_options.width
|
|
local height = options and options.height or timeline_options.height
|
|
local scrollWidth = 800 --placeholder until the timeline receives data
|
|
local scrollHeight = 800 --placeholder until the timeline receives data
|
|
|
|
local frameCanvas = CreateFrame("scrollframe", name, parent, "BackdropTemplate")
|
|
|
|
detailsFramework:Mixin(frameCanvas, detailsFramework.TimeLineFunctions)
|
|
detailsFramework:Mixin(frameCanvas, detailsFramework.OptionsFunctions)
|
|
detailsFramework:Mixin(frameCanvas, detailsFramework.LayoutFrame)
|
|
|
|
frameCanvas.data = {}
|
|
frameCanvas.lines = {}
|
|
frameCanvas.currentScale = 0.5
|
|
frameCanvas:SetSize(width, height)
|
|
|
|
detailsFramework:ApplyStandardBackdrop(frameCanvas)
|
|
|
|
local frameBody = CreateFrame("frame", nil, frameCanvas, "BackdropTemplate")
|
|
frameBody:SetSize(scrollWidth, scrollHeight)
|
|
|
|
frameCanvas:SetScrollChild(frameBody)
|
|
frameCanvas.body = frameBody
|
|
|
|
frameCanvas:BuildOptionsTable(timeline_options, options)
|
|
|
|
--create elapsed time frame
|
|
frameCanvas.elapsedTimeFrame = detailsFramework:CreateElapsedTimeFrame(frameBody, frameCanvas:GetName() and frameCanvas:GetName() .. "ElapsedTimeFrame", timelineOptions)
|
|
|
|
--create horizontal slider
|
|
local horizontalSlider = CreateFrame("slider", frameCanvas:GetName() .. "HorizontalSlider", parent, "BackdropTemplate")
|
|
horizontalSlider.bg = horizontalSlider:CreateTexture(nil, "background")
|
|
horizontalSlider.bg:SetAllPoints(true)
|
|
horizontalSlider.bg:SetTexture(0, 0, 0, 0.5)
|
|
frameCanvas.horizontalSlider = horizontalSlider
|
|
|
|
horizontalSlider:SetBackdrop(frameCanvas.options.slider_backdrop)
|
|
horizontalSlider:SetBackdropColor(unpack(frameCanvas.options.slider_backdrop_color))
|
|
horizontalSlider:SetBackdropBorderColor(unpack(frameCanvas.options.slider_backdrop_border_color))
|
|
|
|
horizontalSlider.thumb = horizontalSlider:CreateTexture(nil, "OVERLAY")
|
|
horizontalSlider.thumb:SetTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
|
|
horizontalSlider.thumb:SetSize(24, 24)
|
|
horizontalSlider.thumb:SetVertexColor(0.6, 0.6, 0.6, 0.95)
|
|
horizontalSlider:SetThumbTexture(horizontalSlider.thumb)
|
|
|
|
horizontalSlider:SetOrientation("horizontal")
|
|
horizontalSlider:SetSize(width + 20, 20)
|
|
horizontalSlider:SetPoint("topleft", frameCanvas, "bottomleft")
|
|
horizontalSlider:SetMinMaxValues(0, scrollWidth)
|
|
horizontalSlider:SetValue(0)
|
|
horizontalSlider:SetScript("OnValueChanged", function(self)
|
|
local _, maxValue = horizontalSlider:GetMinMaxValues()
|
|
local stepValue = ceil(ceil(self:GetValue() * maxValue) / max(maxValue, SMALL_FLOAT))
|
|
if (stepValue ~= horizontalSlider.currentValue) then
|
|
horizontalSlider.currentValue = stepValue
|
|
frameCanvas:SetHorizontalScroll(stepValue)
|
|
end
|
|
end)
|
|
|
|
--create scale slider
|
|
local scaleSlider = CreateFrame("slider", frameCanvas:GetName() .. "ScaleSlider", parent, "BackdropTemplate")
|
|
scaleSlider.bg = scaleSlider:CreateTexture(nil, "background")
|
|
scaleSlider.bg:SetAllPoints(true)
|
|
scaleSlider.bg:SetTexture(0, 0, 0, 0.5)
|
|
scaleSlider:Disable()
|
|
frameCanvas.scaleSlider = scaleSlider
|
|
|
|
scaleSlider:SetBackdrop(frameCanvas.options.slider_backdrop)
|
|
scaleSlider:SetBackdropColor(unpack(frameCanvas.options.slider_backdrop_color))
|
|
scaleSlider:SetBackdropBorderColor(unpack(frameCanvas.options.slider_backdrop_border_color))
|
|
|
|
scaleSlider.thumb = scaleSlider:CreateTexture(nil, "OVERLAY")
|
|
scaleSlider.thumb:SetTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
|
|
scaleSlider.thumb:SetSize(24, 24)
|
|
scaleSlider.thumb:SetVertexColor(0.6, 0.6, 0.6, 0.95)
|
|
scaleSlider:SetThumbTexture(scaleSlider.thumb)
|
|
|
|
scaleSlider:SetOrientation("horizontal")
|
|
scaleSlider:SetSize(width + 20, 20)
|
|
scaleSlider:SetPoint("topleft", horizontalSlider, "bottomleft", 0, -2)
|
|
scaleSlider:SetMinMaxValues(frameCanvas.options.scale_min, frameCanvas.options.scale_max)
|
|
scaleSlider:SetValue(detailsFramework:GetRangeValue(frameCanvas.options.scale_min, frameCanvas.options.scale_max, 0.5))
|
|
|
|
scaleSlider:SetScript("OnValueChanged", function(self)
|
|
local stepValue = ceil(self:GetValue() * 100) / 100
|
|
if (stepValue ~= frameCanvas.currentScale) then
|
|
local current = stepValue
|
|
frameCanvas.currentScale = stepValue
|
|
frameCanvas:RefreshTimeLine()
|
|
end
|
|
end)
|
|
|
|
--create vertical slider
|
|
local verticalSlider = CreateFrame("slider", frameCanvas:GetName() .. "VerticalSlider", parent, "BackdropTemplate")
|
|
verticalSlider.bg = verticalSlider:CreateTexture(nil, "background")
|
|
verticalSlider.bg:SetAllPoints(true)
|
|
verticalSlider.bg:SetTexture(0, 0, 0, 0.5)
|
|
frameCanvas.verticalSlider = verticalSlider
|
|
|
|
verticalSlider:SetBackdrop(frameCanvas.options.slider_backdrop)
|
|
verticalSlider:SetBackdropColor(unpack(frameCanvas.options.slider_backdrop_color))
|
|
verticalSlider:SetBackdropBorderColor(unpack(frameCanvas.options.slider_backdrop_border_color))
|
|
|
|
verticalSlider.thumb = verticalSlider:CreateTexture(nil, "OVERLAY")
|
|
verticalSlider.thumb:SetTexture("Interface\\Buttons\\UI-ScrollBar-Knob")
|
|
verticalSlider.thumb:SetSize(24, 24)
|
|
verticalSlider.thumb:SetVertexColor(0.6, 0.6, 0.6, 0.95)
|
|
verticalSlider:SetThumbTexture(verticalSlider.thumb)
|
|
|
|
verticalSlider:SetOrientation("vertical")
|
|
verticalSlider:SetSize(20, height - 2)
|
|
verticalSlider:SetPoint("topleft", frameCanvas, "topright", 0, 0)
|
|
verticalSlider:SetMinMaxValues(0, scrollHeight)
|
|
verticalSlider:SetValue(0)
|
|
verticalSlider:SetScript("OnValueChanged", function(self)
|
|
frameCanvas:SetVerticalScroll(self:GetValue())
|
|
end)
|
|
|
|
--mouse scroll
|
|
frameCanvas:EnableMouseWheel(true)
|
|
frameCanvas:SetScript("OnMouseWheel", function(self, delta)
|
|
local minValue, maxValue = horizontalSlider:GetMinMaxValues()
|
|
local currentHorizontal = horizontalSlider:GetValue()
|
|
|
|
if (IsShiftKeyDown() and delta < 0) then
|
|
local amountToScroll = frameBody:GetHeight() / 20
|
|
verticalSlider:SetValue(verticalSlider:GetValue() + amountToScroll)
|
|
|
|
elseif (IsShiftKeyDown() and delta > 0) then
|
|
local amountToScroll = frameBody:GetHeight() / 20
|
|
verticalSlider:SetValue(verticalSlider:GetValue() - amountToScroll)
|
|
|
|
elseif (IsControlKeyDown() and delta > 0) then
|
|
scaleSlider:SetValue(min(scaleSlider:GetValue() + 0.1, 1))
|
|
|
|
elseif (IsControlKeyDown() and delta < 0) then
|
|
scaleSlider:SetValue(max(scaleSlider:GetValue() - 0.1, 0.15))
|
|
|
|
elseif (delta < 0 and currentHorizontal < maxValue) then
|
|
local amountToScroll = frameBody:GetWidth() / 20
|
|
horizontalSlider:SetValue(currentHorizontal + amountToScroll)
|
|
|
|
elseif (delta > 0 and maxValue > 1) then
|
|
local amountToScroll = frameBody:GetWidth() / 20
|
|
horizontalSlider:SetValue(currentHorizontal - amountToScroll)
|
|
|
|
end
|
|
end)
|
|
|
|
--mouse drag
|
|
frameBody:SetScript("OnMouseDown", function(self, button)
|
|
local x = GetCursorPosition()
|
|
self.MouseX = x
|
|
|
|
frameBody:SetScript("OnUpdate", function(self, deltaTime)
|
|
local x = GetCursorPosition()
|
|
local deltaX = self.MouseX - x
|
|
local current = horizontalSlider:GetValue()
|
|
horizontalSlider:SetValue(current +(deltaX * 1.2) *((IsShiftKeyDown() and 2) or(IsAltKeyDown() and 0.5) or 1))
|
|
self.MouseX = x
|
|
end)
|
|
end)
|
|
|
|
frameBody:SetScript("OnMouseUp", function(self, button)
|
|
frameBody:SetScript("OnUpdate", nil)
|
|
end)
|
|
|
|
return frameCanvas
|
|
end
|
|
|
|
|
|
--[=[
|
|
local f = CreateFrame("frame", "TestFrame", UIParent)
|
|
f:SetPoint("center")
|
|
f:SetSize(900, 420)
|
|
f:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16, insets = {left = 1, right = 1, top = 0, bottom = 1}})
|
|
|
|
local scroll = DF:CreateTimeLineFrame (f, "$parentTimeLine", {width = 880, height = 400})
|
|
scroll:SetPoint("topleft", f, "topleft", 0, 0)
|
|
|
|
--need fake data to test fills
|
|
scroll:SetData ({
|
|
length = 360,
|
|
defaultColor = {1, 1, 1, 1},
|
|
lines = {
|
|
{text = "player 1", icon = "", timeline = {
|
|
--each table here is a block shown in the line
|
|
--is an indexed table with: [1] time [2] length [3] color (if false, use the default) [4] text [5] icon [6] tooltip: if number = spellID tooltip, if table is text lines
|
|
{1, 10}, {13, 11}, {25, 7}, {36, 5}, {55, 18}, {76, 30}, {105, 20}, {130, 11}, {155, 11}, {169, 7}, {199, 16}, {220, 18}, {260, 10}, {290, 23}, {310, 30}, {350, 10}
|
|
}
|
|
}, --end of line 1
|
|
},
|
|
})
|
|
|
|
|
|
f:Hide()
|
|
|
|
--scroll.body:SetScale(0.5)
|
|
|
|
--]=]
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--error message box
|
|
|
|
function detailsFramework:ShowErrorMessage (errorMessage, titleText)
|
|
|
|
if (not detailsFramework.ErrorMessagePanel) then
|
|
local f = CreateFrame("frame", "DetailsFrameworkErrorMessagePanel", UIParent, "BackdropTemplate")
|
|
f:SetSize(400, 120)
|
|
f:SetFrameStrata("FULLSCREEN")
|
|
f:SetPoint("center", UIParent, "center", 0, 100)
|
|
f:EnableMouse(true)
|
|
f:SetMovable(true)
|
|
f:RegisterForDrag ("LeftButton")
|
|
f:SetScript("OnDragStart", function() f:StartMoving() end)
|
|
f:SetScript("OnDragStop", function() f:StopMovingOrSizing() end)
|
|
f:SetScript("OnMouseDown", function(self, button) if (button == "RightButton") then f:Hide() end end)
|
|
table.insert(UISpecialFrames, "DetailsFrameworkErrorMessagePanel")
|
|
detailsFramework.ErrorMessagePanel = f
|
|
|
|
detailsFramework:CreateTitleBar (f, "Details! Framework Error!")
|
|
detailsFramework:ApplyStandardBackdrop(f)
|
|
|
|
local errorLabel = f:CreateFontString(nil, "overlay", "GameFontNormal")
|
|
errorLabel:SetPoint("top", f, "top", 0, -25)
|
|
errorLabel:SetJustifyH("center")
|
|
errorLabel:SetSize(360, 66)
|
|
f.errorLabel = errorLabel
|
|
|
|
local button_text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")
|
|
local options_dropdown_template = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")
|
|
|
|
local closeButton = detailsFramework:CreateButton(f, nil, 60, 20, "close", nil, nil, nil, nil, nil, nil, options_dropdown_template)
|
|
closeButton:SetPoint("bottom", f, "bottom", 0, 5)
|
|
f.closeButton = closeButton
|
|
|
|
closeButton:SetClickFunction(function()
|
|
f:Hide()
|
|
end)
|
|
|
|
f.ShowAnimation = detailsFramework:CreateAnimationHub (f, function()
|
|
f:SetBackdropBorderColor(0, 0, 0, 0)
|
|
f.TitleBar:SetBackdropBorderColor(0, 0, 0, 0)
|
|
end, function()
|
|
f:SetBackdropBorderColor(0, 0, 0, 1)
|
|
f.TitleBar:SetBackdropBorderColor(0, 0, 0, 1)
|
|
end)
|
|
detailsFramework:CreateAnimation(f.ShowAnimation, "scale", 1, .075, .2, .2, 1.1, 1.1, "center", 0, 0)
|
|
detailsFramework:CreateAnimation(f.ShowAnimation, "scale", 2, .075, 1, 1, .90, .90, "center", 0, 0)
|
|
|
|
f.FlashTexture = f:CreateTexture(nil, "overlay")
|
|
f.FlashTexture:SetColorTexture(1, 1, 1, 1)
|
|
f.FlashTexture:SetAllPoints()
|
|
|
|
f.FlashAnimation = detailsFramework:CreateAnimationHub (f.FlashTexture, function() f.FlashTexture:Show() end, function() f.FlashTexture:Hide() end)
|
|
detailsFramework:CreateAnimation(f.FlashAnimation, "alpha", 1, .075, 0, .05)
|
|
detailsFramework:CreateAnimation(f.FlashAnimation, "alpha", 2, .075, .1, 0)
|
|
|
|
f:Hide()
|
|
end
|
|
|
|
detailsFramework.ErrorMessagePanel:Show()
|
|
detailsFramework.ErrorMessagePanel.errorLabel:SetText(errorMessage)
|
|
detailsFramework.ErrorMessagePanel.TitleLabel:SetText(titleText)
|
|
detailsFramework.ErrorMessagePanel.ShowAnimation:Play()
|
|
detailsFramework.ErrorMessagePanel.FlashAnimation:Play()
|
|
end
|
|
|
|
--[[
|
|
DF:SetPointOffsets(frame, xOffset, yOffset)
|
|
|
|
Set an offset into the already existing offset of the frame
|
|
If passed xOffset:1 and yOffset:1 and the frame has 1 -1, the new offset will be 2 -2
|
|
This function is great to create a 1 knob for distance
|
|
|
|
@frame: a frame to have the offsets changed
|
|
@xOffset: the amount to apply into the x offset
|
|
@yOffset: the amount to apply into the y offset
|
|
--]]
|
|
function detailsFramework:SetPointOffsets(frame, xOffset, yOffset)
|
|
for i = 1, frame:GetNumPoints() do
|
|
local anchor1, anchorTo, anchor2, x, y = frame:GetPoint(i)
|
|
x = x or 0
|
|
y = y or 0
|
|
|
|
if (x >= 0) then
|
|
xOffset = x + xOffset
|
|
|
|
elseif (x < 0) then
|
|
xOffset = x - xOffset
|
|
end
|
|
|
|
if (y >= 0) then
|
|
yOffset = y + yOffset
|
|
|
|
elseif (y < 0) then
|
|
yOffset = y - yOffset
|
|
end
|
|
|
|
frame:SetPoint(anchor1, anchorTo, anchor2, xOffset, yOffset)
|
|
end
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
--list box
|
|
|
|
detailsFramework.ListboxFunctions = {
|
|
scrollRefresh = function(self, data, offset, totalLines)
|
|
for i = 1, totalLines do
|
|
local index = i + offset
|
|
local lineData = data[index] --what is shown in the textentries, array
|
|
|
|
if (lineData) then
|
|
local line = self:GetLine(i)
|
|
line.dataIndex = index
|
|
line.deleteButton:SetClickFunction(detailsFramework.ListboxFunctions.deleteEntry, data, index)
|
|
line.indexText:SetText(index)
|
|
|
|
local amountEntries = #lineData
|
|
for o = 1, amountEntries do
|
|
--data
|
|
local textEntry = line.widgets[o]
|
|
textEntry.dataTable = lineData
|
|
textEntry.dataTableIndex = o
|
|
local text = lineData[o]
|
|
textEntry:SetText(text)
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
|
|
addEntry = function(self)
|
|
local frameCanvas = self:GetParent()
|
|
local data = frameCanvas.data
|
|
local newEntry = {}
|
|
for i = 1, frameCanvas.headerLength do
|
|
table.insert(newEntry, "")
|
|
end
|
|
table.insert(data, newEntry)
|
|
frameCanvas.scrollBox:Refresh()
|
|
end,
|
|
|
|
deleteEntry = function(self, button, data, index)
|
|
tremove(data, index)
|
|
--get the line, get the scrollframe
|
|
self:GetParent():GetParent():Refresh()
|
|
end,
|
|
|
|
createScrollLine = function(self, index)
|
|
local listBox = self:GetParent()
|
|
local line = CreateFrame("frame", self:GetName().. "line_" .. index, self, "BackdropTemplate")
|
|
|
|
line:SetPoint("topleft", self, "topleft", 1, -((index-1)*(self.lineHeight+1)) - 1)
|
|
line:SetSize(self:GetWidth() - 28, self.lineHeight) -- -28 space for the scrollbar
|
|
|
|
local options = listBox.options
|
|
line:SetBackdrop(options.line_backdrop)
|
|
line:SetBackdropColor(unpack(options.line_backdrop_color))
|
|
line:SetBackdropBorderColor(unpack(options.line_backdrop_border_color))
|
|
|
|
detailsFramework:Mixin(line, detailsFramework.HeaderFunctions)
|
|
|
|
line.widgets = {}
|
|
|
|
for i = 1, (listBox.headerLength+2) do --+2 to add the delete button and index
|
|
local headerColumn = listBox.headerTable[i]
|
|
|
|
if (headerColumn.isDelete) then
|
|
local deleteButton = detailsFramework:CreateButton(line, detailsFramework.ListboxFunctions.deleteEntry, 20, self.lineHeight, "X", listBox.data, index, nil, nil, nil, nil, detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), detailsFramework:GetTemplate("font", "ORANGE_FONT_TEMPLATE"))
|
|
line.deleteButton = deleteButton
|
|
line:AddFrameToHeaderAlignment(deleteButton)
|
|
|
|
elseif (headerColumn.isIndex) then
|
|
local indexText = detailsFramework:CreateLabel(line)
|
|
line.indexText = indexText
|
|
line:AddFrameToHeaderAlignment(indexText)
|
|
|
|
elseif (headerColumn.text) then
|
|
local template = detailsFramework.table.copy({}, detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"))
|
|
template.backdropcolor = {.1, .1, .1, .7}
|
|
template.backdropbordercolor = {.2, .2, .2, .6}
|
|
|
|
local textEntry = detailsFramework:CreateTextEntry(line, function()end, headerColumn.width, self.lineHeight, nil, nil, nil, template)
|
|
textEntry:SetHook("OnEditFocusGained", function() textEntry:HighlightText(0) end)
|
|
textEntry:SetHook("OnEditFocusLost", function()
|
|
textEntry:HighlightText(0, 0)
|
|
local text = textEntry.text
|
|
local dataTable = textEntry.dataTable
|
|
dataTable[textEntry.dataTableIndex] = text
|
|
end)
|
|
table.insert(line.widgets, textEntry)
|
|
line:AddFrameToHeaderAlignment(textEntry)
|
|
end
|
|
end
|
|
|
|
line:AlignWithHeader(listBox.header, "left")
|
|
return line
|
|
end,
|
|
|
|
SetData = function(frameCanvas, newData)
|
|
if (type(newData) ~= "table") then
|
|
error("ListBox:SetData received an invalid newData on parameter 2.")
|
|
return
|
|
end
|
|
|
|
frameCanvas.data = newData
|
|
frameCanvas.scrollBox:SetData(newData)
|
|
frameCanvas.scrollBox:Refresh()
|
|
end,
|
|
}
|
|
|
|
local listbox_options = {
|
|
width = 800,
|
|
height = 600,
|
|
auto_width = true,
|
|
line_height = 16,
|
|
line_backdrop = {bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true},
|
|
line_backdrop_color = {.1, .1, .1, .6},
|
|
line_backdrop_border_color = {0, 0, 0, .5},
|
|
}
|
|
|
|
--@parent: parent frame
|
|
--@name: name of the frame to be created
|
|
--@data: table with current data to fill the column, this table are also used for values changed or added
|
|
--@options: table with options to overwrite the default setting from 'listbox_options'
|
|
--@header: a table to create a header widget
|
|
--@header_options: a table with options to overwrite the default header options
|
|
function detailsFramework:CreateListBox(parent, name, data, options, headerTable, headerOptions)
|
|
|
|
options = options or {}
|
|
name = name or "ListboxUnamed_" .. (math.random(100000, 1000000))
|
|
|
|
--canvas
|
|
local frameCanvas = CreateFrame("scrollframe", name, parent, "BackdropTemplate")
|
|
detailsFramework:Mixin(frameCanvas, detailsFramework.ListboxFunctions)
|
|
detailsFramework:Mixin(frameCanvas, detailsFramework.OptionsFunctions)
|
|
detailsFramework:Mixin(frameCanvas, detailsFramework.LayoutFrame)
|
|
frameCanvas.headerTable = headerTable
|
|
|
|
if (not data or type(data) ~= "table") then
|
|
error("CreateListBox() parameter 3 'data' must be a table.")
|
|
end
|
|
|
|
frameCanvas.data = data
|
|
frameCanvas.lines = {}
|
|
detailsFramework:ApplyStandardBackdrop(frameCanvas)
|
|
frameCanvas:BuildOptionsTable(listbox_options, options)
|
|
|
|
--header
|
|
--check for default values in the header
|
|
headerTable = headerTable or {
|
|
{text = "Spell Id", width = 70},
|
|
{text = "Spell Name", width = 70},
|
|
}
|
|
headerOptions = headerOptions or {
|
|
padding = 2,
|
|
}
|
|
|
|
--each header is an entry in the data, if the header has 4 indexes the data has sub tables with 4 indexes as well
|
|
frameCanvas.headerLength = #headerTable
|
|
|
|
--add the detele line column into the header frame
|
|
table.insert(headerTable, 1, {text = "#", width = 20, isIndex = true}) --isDelete signals the createScrollLine() to make the delete button for the line
|
|
table.insert(headerTable, {text = "Delete", width = 50, isDelete = true}) --isDelete signals the createScrollLine() to make the delete button for the line
|
|
|
|
local header = detailsFramework:CreateHeader(frameCanvas, headerTable, headerOptions)
|
|
--set the header point
|
|
header:SetPoint("topleft", frameCanvas, "topleft", 5, -5)
|
|
frameCanvas.header = header
|
|
|
|
--auto size
|
|
if (frameCanvas.options.auto_width) then
|
|
local width = 10 --padding 5 on each side
|
|
width = width + 20 --scrollbar reserved space
|
|
local headerPadding = headerOptions.padding or 0
|
|
|
|
for _, header in pairs(headerTable) do
|
|
if (header.width) then
|
|
width = width + header.width + headerPadding
|
|
end
|
|
end
|
|
|
|
frameCanvas.options.width = width
|
|
frameCanvas:SetWidth(width)
|
|
end
|
|
|
|
local width = frameCanvas.options.width
|
|
local height = frameCanvas.options.height
|
|
|
|
frameCanvas:SetSize(frameCanvas.options.width, height)
|
|
|
|
--scroll frame
|
|
local lineHeight = frameCanvas.options.line_height
|
|
--calc the size of the space occupied by the add button, header etc
|
|
local lineAmount = floor((height - 60) / lineHeight)
|
|
|
|
-- -12 is padding: 5 on top, 7 bottom, 2 header scrollbar blank space | -24 to leave space to the add button
|
|
local scrollBox = detailsFramework:CreateScrollBox(frameCanvas, "$parentScrollbox", frameCanvas.scrollRefresh, data, width-4, height - header:GetHeight() - 12 - 24, lineAmount, lineHeight)
|
|
scrollBox:SetPoint("topleft", header, "bottomleft", 0, -2)
|
|
scrollBox:SetPoint("topright", header, "bottomright", 0, -2) -- -20 for the scrollbar
|
|
detailsFramework:ReskinSlider(scrollBox)
|
|
scrollBox.lineHeight = lineHeight
|
|
scrollBox.lineAmount = lineAmount
|
|
frameCanvas.scrollBox = scrollBox
|
|
|
|
for i = 1, lineAmount do
|
|
scrollBox:CreateLine(frameCanvas.createScrollLine)
|
|
end
|
|
|
|
scrollBox:Refresh()
|
|
|
|
--add line button
|
|
local addLineButton = detailsFramework:CreateButton(frameCanvas, detailsFramework.ListboxFunctions.addEntry, 80, 20, "Add", nil, nil, nil, nil, nil, nil, detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), detailsFramework:GetTemplate("font", "ORANGE_FONT_TEMPLATE"))
|
|
addLineButton:SetPoint("topleft", scrollBox, "bottomleft", 0, -4)
|
|
|
|
return frameCanvas
|
|
end
|
|
|
|
--[=[ -- test case
|
|
|
|
local pframe = ListBoxTest or CreateFrame("frame", "ListBoxTest", UIParent)
|
|
pframe:SetSize(900, 700)
|
|
pframe:SetPoint("left")
|
|
|
|
local data = {{254154, "spell name 1", 45}, {299154, "spell name 2", 05}, {354154, "spell name 3", 99}}
|
|
local headerTable = {
|
|
{text = "spell id", width = 120},
|
|
{text = "spell name", width = 180},
|
|
{text = "number", width = 90},
|
|
}
|
|
|
|
local listbox = DetailsFramework:CreateListBox(pframe, "$parentlistbox", data, nil, headerTable, nil)
|
|
listbox:SetPoint("topleft", pframe, "topleft", 10, -10)
|
|
|
|
--]=]
|
|
|
|
|