ee0b350aba
- Dungeon followers now correctly show into the damage done section. - Fixed an error while statusbar plugin options. - Framework update. - Mythic Dungeon Plus code has been separated into six files (was just 2), this will help with the organization and maintenance of the code.
5807 lines
191 KiB
Lua
5807 lines
191 KiB
Lua
|
|
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 = 1,
|
|
min_width = 0,
|
|
height = 1,
|
|
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 _, _, _, toc = GetBuildInfo()
|
|
if ((ColorPickerFrame and ColorPickerFrame.SetupColorPickerAndShow) or toc >= 100205) then -- maybe fallback to only check CPF in the future
|
|
local color_pick_func = function(...)
|
|
local r, g, b = ColorPickerFrame:GetColorRGB()
|
|
local a = ColorPickerFrame:GetColorAlpha()
|
|
ColorPickerFrame:dcallback (r, g, b, a, ColorPickerFrame.dframe)
|
|
end
|
|
|
|
local color_pick_func_cancel = function()
|
|
local r, g, b, a = ColorPickerFrame.previousValues.r, ColorPickerFrame.previousValues.g, ColorPickerFrame.previousValues.b, ColorPickerFrame.previousValues.a
|
|
ColorPickerFrame.Content.ColorPicker:SetColorRGB(r, g, b)
|
|
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.previousAlpha = alpha
|
|
ColorPickerFrame:SetParent(UIParent)
|
|
ColorPickerFrame:SetFrameStrata("tooltip")
|
|
|
|
local info = {
|
|
swatchFunc = color_pick_func,
|
|
hasOpacity = alpha and true,
|
|
opacityFunc = color_pick_func,
|
|
opacity = alpha,
|
|
previousValues = {r = r, g = g, b = b, a = alpha},
|
|
cancelFunc = color_pick_func_cancel,
|
|
r = r,
|
|
g = g,
|
|
b = b,
|
|
}
|
|
--OpenColorPicker(info)
|
|
ColorPickerFrame:SetupColorPickerAndShow(info)
|
|
|
|
end
|
|
else
|
|
local color_pick_func = function()
|
|
local r, g, b = ColorPickerFrame:GetColorRGB()
|
|
local a = OpacitySliderFrame:GetValue()
|
|
a = math.abs(a - 1)
|
|
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()
|
|
a = math.abs(a - 1)
|
|
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
|
|
|
|
alpha = math.abs(alpha - 1)
|
|
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
|
|
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 : frame
|
|
---@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 = 3,
|
|
color = {.1, .1, .1, 0.98},
|
|
border_color = {.05, .05, .05, 0.834},
|
|
use_titlebar = true,
|
|
titlebar_height = 26,
|
|
}
|
|
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()
|
|
|
|
if (self.options.rounded_corner_preset) then
|
|
checkbox:SetBackdrop(nil)
|
|
detailsFramework:AddRoundedCornersToFrame(checkbox, self.options.rounded_corner_preset)
|
|
end
|
|
|
|
if (self.options.checked_texture) then
|
|
checkbox:SetCheckedTexture(self.options.checked_texture, self.options.checked_texture_offset_x, self.options.checked_texture_offset_y)
|
|
end
|
|
|
|
checkbox.Icon = detailsFramework:CreateImage(checkbox, "", 16, 16)
|
|
checkbox.Label = detailsFramework:CreateLabel(checkbox, "")
|
|
self.allCheckBoxes[#self.allCheckBoxes + 1] = checkbox
|
|
|
|
if (self.options.on_create_checkbox) then
|
|
--use dispatch
|
|
detailsFramework:QuickDispatch(self.options.on_create_checkbox, self, checkbox)
|
|
end
|
|
|
|
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
|
|
|
|
if (radioGroup.options.on_click_option) then
|
|
detailsFramework:QuickDispatch(radioGroup.options.on_click_option, radioGroup, checkbox, 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 bIsChecked = type(optionTable.get) == "function" and detailsFramework:Dispatch(optionTable.get) or false
|
|
checkbox:SetValue(bIsChecked)
|
|
|
|
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", self.AnchorOptions.icon_offset_x, 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
|
|
|
|
if (optionTable.mask) then
|
|
checkbox.Icon:SetMask(optionTable.mask)
|
|
else
|
|
checkbox.Icon:SetMask("")
|
|
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
|
|
|
|
if (not self.AnchorOptions.width) then
|
|
self:SetWidth(totalWidth)
|
|
else
|
|
self:SetWidth(self.AnchorOptions.width)
|
|
end
|
|
|
|
if (not self.AnchorOptions.height) then
|
|
self:SetHeight(maxHeight)
|
|
else
|
|
self:SetHeight(self.AnchorOptions.height)
|
|
end
|
|
|
|
self.AnchorOptions.start_y = -5
|
|
|
|
--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)
|
|
|
|
--]=]
|
|
|