Major upgrade for alpha testers

This commit is contained in:
Tercio Jose
2023-11-30 16:13:14 -03:00
parent 319fe4c84e
commit 0ff046b500
24 changed files with 2616 additions and 1399 deletions
+3
View File
@@ -112,6 +112,7 @@
---@field __destroyedBy string
---@field amountCasts {[string]: table<string, number>}
---@field instance_type instancetype "raid" or "party" or "pvp" or "arena" or "none" or "scenario"
---@field run_time number
---@field end_time number
---@field start_time number
---@field combat_counter number
@@ -130,10 +131,12 @@
---@field is_boss table
---@field is_world_trash_combat boolean when true this combat is a regular combat done in the world, not in a dungeon, raid, battleground, arena, ...
---@field player_last_events table<string, table[]> record the latest events of each player, latter used to build the death log
---@field GetCombatType fun(combat: combat) : number
---@field GetCombatUID fun(combat: combat) : uniquecombatid
---@field GetTimeData fun(combat: combat, dataName: string) : table
---@field GetPhases fun(combat: combat) : table
---@field GetCombatTime fun(combat) : number
---@field GetRunTime fun(combat) : number
---@field GetDeaths fun(combat) : table --get the table which contains the deaths of the combat
---@field GetStartTime fun(combat: combat) : number
---@field SetStartTime fun(combat: combat, time: number)
+5
View File
@@ -855,6 +855,11 @@ end
debuffTrackedAuraScrollBox:SetPoint("topleft", auraPanel_Auto, "topleft", 16 +(scrollWidth * 2) + xLocation, y)
buffTrackedAuraScrollBox:SetPoint("topleft", auraPanel_Auto, "topleft", 24 +(scrollWidth * 3) + xLocation, y)
buffTrackedAuraScrollBox:GetTitleFontString():SetText(newAuraPanel.LocTexts.BUFFS_TRACKED)
debuffTrackedAuraScrollBox:GetTitleFontString():SetText(newAuraPanel.LocTexts.DEBUFFS_TRACKED)
buffIgnoredAuraScrollBox:GetTitleFontString():SetText(newAuraPanel.LocTexts.BUFFS_IGNORED)
debuffIgnoredAuraScrollBox:GetTitleFontString():SetText(newAuraPanel.LocTexts.DEBUFFS_IGNORED)
newAuraPanel.buff_ignored = buffIgnoredAuraScrollBox
newAuraPanel.debuff_ignored = debuffIgnoredAuraScrollBox
newAuraPanel.buff_tracked = buffTrackedAuraScrollBox
+963 -1031
View File
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -45,6 +45,7 @@
---@class detailsframework
---@field dversion number
---@field internalFunctions table
---@field OptionsFunctions df_optionsmixin
---@field GlobalWidgetControlNames table
---@field RoundedCornerPanelMixin df_roundedcornermixin
@@ -56,7 +57,7 @@
---@field EditorMixin df_editormixin
---@field ClassCache {ID:number, Name:string, FileString:string, Texture:string, TexCoord:number[]}[] only available after calling GetClassList()
---@field Math df_math
---@field FontOutlineFlags {key1:outline, key2:string}[]
---@field FontOutlineFlags table<outline, boolean>
---@field table df_table_functions
---@field AnchorPoints string[]
---@field ClassFileNameToIndex table<string, number> engClass -> classIndex
@@ -102,7 +103,7 @@
---@field CommaValue fun(self:table, value:number) : string convert a number to a string with commas, e.g. 1000000 -> 1,000,000
---@field SplitTextInLines fun(self:table, text:string) : string[] split a text into lines
---@field UnitGroupRolesAssigned fun(unitId: unit, bUseSupport:boolean, specId: specializationid) : string there's no self here
---@field SetAnchor fun(self:table, widget:uiobject, anchorTable:df_anchor, anchorTo:uiobject)
---@field SetAnchor fun(self:table, widget:uiobject, anchorTable:df_anchor, anchorTo:uiobject?) only adjust the anchors of a widget, does not save values
---@field AddTextureToText fun(text:string, textureInfo:table, bAddSpace:boolean?, bAddAfterText:boolean) : string textureInfo is a table with .texture .width .height .coords{left, right, top, bottom}
---@field CreateTextureInfo fun(texture:atlasname|texturepath|textureid, width:number?, height:number?, left:number?, right:number?, top:number?, bottom:number?, imageWidthnumber?, imageHeightnumber?) : table
---@field ApplyStandardBackdrop fun(self:table, frame:frame, bUseSolidColor:boolean?, alphaScale:number?)
@@ -132,8 +133,10 @@
---@field CreateAuraScrollBox fun(self:table, parent:frame, name:string?, data:table?, onRemoveCallback:function?, options:table?) : df_aurascrollbox
---@field CreateGridScrollBox fun(self:table, parent:frame, name:string?, refreshFunc:function, data:table?, createColumnFrameFunc:function, options:table?) : df_gridscrollbox
---@field CreateCanvasScrollBox fun(self:table, parent:frame, child:frame?, name:string?, options:table?) : df_canvasscrollbox
---@field CreateTabContainer fun(self:table, parent:frame, title:string, frameName:string, tabList:df_tabinfotable[], optionsTable:table?, hookList:table?, languageInfo:table?) : df_tabcontainer
---@field GetSizeFromPercent fun(self:table, uiObject:uiobject, percent:number) : number get the min size of a uiObject and multiply it by the percent passed
---@field BuildMenu fun(self:table, parent:frame, menuOptions:df_menu_table[], xOffset:number?, yOffset:number?, height:number?, useColon:boolean?, textTemplate:table?, dropdownTemplate:table?, switchTemplate:table?, switchIsCheckbox:boolean?, sliderTemplate:table?, buttonTemplate:table?, valueChangeHook:function?)
---@field BuildMenuVolatile fun(self:table, parent:frame, menuOptions:df_menu_table[], xOffset:number?, yOffset:number?, height:number?, useColon:boolean?, textTemplate:table?, dropdownTemplate:table?, switchTemplate:table?, switchIsCheckbox:boolean?, sliderTemplate:table?, buttonTemplate:table?, valueChangeHook:function?)
---@field
---@field
+7 -9
View File
@@ -986,16 +986,13 @@ function DetailsFrameworkDropDownOnHide(self)
object:Close()
end
local iconSizeTable = {16, 16}
function DF:BuildDropDownFontList(onClick, icon, iconTexcoord, iconSize)
local fontTable = {}
if (type(iconSize) ~= "table") then
iconSize = {iconSize or 16, iconSize or 16}
end
local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0")
for name, fontPath in pairs(SharedMedia:HashTable("font")) do
fontTable[#fontTable+1] = {value = name, label = name, onclick = onClick, icon = icon, iconsize = iconSize, texcoord = iconTexcoord, font = fontPath, descfont = "abcdefg ABCDEFG"}
fontTable[#fontTable+1] = {value = name, label = name, onclick = onClick, icon = icon, iconsize = iconSizeTable, texcoord = iconTexcoord, font = fontPath, descfont = "abcdefg ABCDEFG"}
end
table.sort(fontTable, function(t1, t2) return t1.label < t2.label end)
@@ -1141,11 +1138,12 @@ function DF:CreateOutlineListGenerator(callback)
local newGenerator = function()
local dropdownOptions = {}
for i, outlineInfo in ipairs(DF.FontOutlineFlags) do
local outlineName, outlineLoc = unpack(outlineInfo)
for index, outlineInfo in pairs(DF.FontOutlineFlags) do
local outlineValue = outlineInfo[1]
local outlineName = outlineInfo[2]
table.insert(dropdownOptions, {
label = outlineLoc,
value = outlineName,
label = outlineName,
value = outlineValue,
onclick = callback
})
end
+657 -100
View File
@@ -14,7 +14,7 @@ local _
--[=[
file description: this file has the code for the object editor
the object editor itself is a frame and has a scrollframe as canvas showing another frame where there's the options for the editing object
--]=]
@@ -22,10 +22,10 @@ local _
--the mapTable is a table with the attribute name as a key, and the value is the profile key. For example, {["size"] = "text_size"} means profileTable["text_size"] = 10.
---@class df_editor_attribute
---@field name string
---@field label string
---@field name string?
---@field label string?
---@field widget string
---@field default any
---@field default any?
---@field minvalue number?
---@field maxvalue number?
---@field step number?
@@ -55,12 +55,15 @@ local attributes = {
name = "font",
label = "Font",
widget = "fontdropdown",
setter = function(widget, value) widget:SetFont(value, select(2, widget:GetFont())) end
setter = function(widget, value)
local font = LibStub:GetLibrary("LibSharedMedia-3.0"):Fetch("font", value)
widget:SetFont(font, select(2, widget:GetFont()))
end
},
{
name = "color",
label = "Color",
widget = "colordropdown",
widget = "color",
setter = function(widget, value) widget:SetTextColor(unpack(value)) end
},
{
@@ -69,6 +72,7 @@ local attributes = {
widget = "range",
setter = function(widget, value) widget:SetAlpha(value) end
},
{widget = "blank"},
{
name = "shadow",
label = "Draw Shadow",
@@ -78,7 +82,7 @@ local attributes = {
{
name = "shadowcolor",
label = "Shadow Color",
widget = "colordropdown",
widget = "color",
setter = function(widget, value) widget:SetShadowColor(unpack(value)) end
},
{
@@ -103,6 +107,7 @@ local attributes = {
widget = "outlinedropdown",
setter = function(widget, value) widget:SetFont(widget:GetFont(), select(2, widget:GetFont()), value) end
},
{widget = "blank"},
{
name = "anchor",
label = "Anchor",
@@ -113,16 +118,16 @@ local attributes = {
name = "anchoroffsetx",
label = "Anchor X Offset",
widget = "range",
minvalue = -20,
maxvalue = 20,
minvalue = -100,
maxvalue = 100,
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
},
{
name = "anchoroffsety",
label = "Anchor Y Offset",
widget = "range",
minvalue = -20,
maxvalue = 20,
minvalue = -100,
maxvalue = 100,
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
},
{
@@ -134,56 +139,59 @@ local attributes = {
maxvalue = math.pi*2,
setter = function(widget, value) widget:SetRotation(value) end
},
{
name = "scale",
label = "Scale",
widget = "range",
usedecimals = true,
minvalue = 0.65,
maxvalue = 2.5,
setter = function(widget, value) widget:SetScale(value) end
},
}
}
local profileTable = {
spellname_text_size = 10,
spellname_text_font = "Arial Narrow",
spellname_text_color = {1, 1, 1, 1},
spellname_text_outline = "NONE",
spellname_text_shadow_color = {0, 0, 0, 1},
spellname_text_shadow_color_offset = {1, -1},
spellname_text_anchor = {side = 9, x = 0, y = 0},
}
--create a map table for the profile table
local mapTable = {
text = "text test",
size = "spellname_text_size",
font = "spellname_text_font",
color = "spellname_text_color",
outline = "spellname_text_outline",
shadowcolor = "spellname_text_shadow_color",
shadowoffsetx = "spellname_text_shadow_color_offset[1]",
shadowoffsety = "spellname_text_shadow_color_offset[2]",
anchor = "spellname_text_anchor.side",
anchoroffsetx = "spellname_text_anchor.x",
anchoroffsety = "spellname_text_anchor.y",
}
local table_path = {
shadowWidth = "text_settings[1].width",
shadowHeight = "text_settings[1].height",
shadowEnabled = "text_settings.settings.enabled",
text = "text_settings.settings.text.current_text",
}
local text_settings = {
shadowWidth = {{width = 100}},
shadowHeight = {{height = 100}},
shadowEnabled = {settings = {enabled = true}},
text = {settings = {text = {current_text = "hellow world"}}},
}
---@class df_editormixin : table
---@field GetAllRegisteredObjects fun(self:df_editor):df_editor_objectinfo[]
---@field GetEditingObject fun(self:df_editor):uiobject
---@field GetEditingOptions fun(self:df_editor):df_editobjectoptions
---@field GetExtraOptions fun(self:df_editor):table
---@field GetEditingProfile fun(self:df_editor):table, table
---@field GetOnEditCallback fun(self:df_editor):function
---@field GetOptionsFrame fun(self:df_editor):frame
---@field GetCanvasScrollBox fun(self:df_editor):df_canvasscrollbox
---@field EditObject fun(self:df_editor, object:uiobject, profileTable:table, profileKeyMap:table, callback:function)
---@field GetObjectSelector fun(self:df_editor):df_scrollbox
---@field EditObject fun(self:df_editor, object:uiobject, profileTable:table, profileKeyMap:table, extraOptions:table?, callback:function?, options:df_editobjectoptions?)
---@field PrepareObjectForEditing fun(self:df_editor)
---@field CreateMoverGuideLines fun(self:df_editor)
---@field GetOverTheTopFrame fun(self:df_editor):frame
---@field GetMoverFrame fun(self:df_editor):frame
---@field StartObjectMovement fun(self:df_editor, anchorSettings:df_anchor)
---@field StopObjectMovement fun(self:df_editor)
---@class df_editobjectoptions : table
---@field use_colon boolean if true a colon is shown after the option name
---@field can_move boolean if true the object can be moved
---@field use_guide_lines boolean if true guide lines are shown when the object is being moved
---@type df_editobjectoptions
local editObjectDefaultOptions = {
use_colon = true,
can_move = true,
use_guide_lines = true,
}
local getParentTable = function(profileTable, profileKey)
local parentPath
if (profileKey:match("%]$")) then
parentPath = profileKey:gsub("%s*%[.*%]%s*$", "")
else
parentPath = profileKey:gsub("%.[^.]*$", "")
end
local parentTable = detailsFramework.table.getfrompath(profileTable, parentPath)
return parentTable
end
detailsFramework.EditorMixin = {
---@param self df_editor
@@ -191,6 +199,18 @@ detailsFramework.EditorMixin = {
return self.editingObject
end,
---@param self df_editor
---@return df_editobjectoptions
GetEditingOptions = function(self)
return self.editingOptions
end,
---@param self df_editor
---@return table
GetExtraOptions = function(self)
return self.editingExtraOptions
end,
---@param self df_editor
---@return table, table
GetEditingProfile = function(self)
@@ -207,28 +227,117 @@ detailsFramework.EditorMixin = {
return self.optionsFrame
end,
GetOverTheTopFrame = function(self)
return self.overTheTopFrame
end,
GetMoverFrame = function(self)
return self.moverFrame
end,
GetCanvasScrollBox = function(self)
return self.canvasScrollBox
end,
---@param self df_editor
---@param object uiobject
---@param profileTable table
---@param profileKeyMap table
---@param callback function calls when an attribute is changed with the payload: editingObject, optionName, newValue, profileTable, profileKey
EditObject = function(self, object, profileTable, profileKeyMap, callback)
assert(type(object) == "table", "EditObject(object) expects an UIObject on first parameter.")
assert(type(profileTable) == "table", "EditObject(object) expects a table on second parameter.")
assert(object.GetObjectType, "EditObject(object) expects an UIObject on first parameter.")
GetObjectSelector = function(self)
return self.objectSelector
end,
EditObjectById = function(self, id)
---@type df_editor_objectinfo
local objectRegistered = self:GetObjectById(id)
assert(type(objectRegistered) == "table", "EditObjectById() object not found.")
self:EditObject(objectRegistered)
end,
EditObjectByIndex = function(self, index)
---@type df_editor_objectinfo
local objectRegistered = self:GetObjectByIndex(index)
assert(type(objectRegistered) == "table", "EditObjectById() object not found.")
self:EditObject(objectRegistered)
end,
---@param self df_editor
---@param registeredObject df_editor_objectinfo
EditObject = function(self, registeredObject)
--clear previous values
self.editingObject = nil
self.editingProfileMap = nil
self.editingProfileTable = nil
self.editingOptions = nil
self.editingExtraOptions = nil
self.onEditCallback = nil
local object = registeredObject.object
local profileTable = registeredObject.profiletable
local profileKeyMap = registeredObject.profilekeymap
local extraOptions = registeredObject.extraoptions
local callback = registeredObject.callback
local options = registeredObject.options
--as there's no other place which this members are set, there is no need to create setter functions
self.editingObject = object
self.editingProfileMap = profileKeyMap
self.editingProfileTable = profileTable
self.onEditCallback = callback
self.editingOptions = options
self.editingExtraOptions = extraOptions
if (type(callback) == "function") then
self.onEditCallback = callback
end
self:PrepareObjectForEditing()
end,
---@param self df_editor
CreateMoverGuideLines = function(self)
local overTheTopFrame = self:GetOverTheTopFrame()
local moverFrame = self:GetMoverFrame()
self.moverGuideLines = {
left = overTheTopFrame:CreateTexture(nil, "overlay"),
right = overTheTopFrame:CreateTexture(nil, "overlay"),
top = overTheTopFrame:CreateTexture(nil, "overlay"),
bottom = overTheTopFrame:CreateTexture(nil, "overlay"),
}
for side, texture in pairs(self.moverGuideLines) do
texture:SetColorTexture(.8, .8, .8, 0.1)
texture:SetSize(1, 1)
texture:SetDrawLayer("overlay", 7)
texture:Hide()
if (side == "left" or side == "right") then
texture:SetHeight(1)
texture:SetWidth(GetScreenWidth())
else
texture:SetWidth(1)
texture:SetHeight(GetScreenHeight())
end
end
end,
UpdateGuideLinesAnchors = function(self)
local object = self:GetEditingObject()
for side, texture in pairs(self.moverGuideLines) do
texture:ClearAllPoints()
if (side == "left" or side == "right") then
if (side == "left") then
texture:SetPoint("right", object, "left", -2, 0)
else
texture:SetPoint("left", object, "right", 2, 0)
end
else
if (side == "top") then
texture:SetPoint("bottom", object, "top", 0, 2)
else
texture:SetPoint("top", object, "bottom", 0, -2)
end
end
end
end,
PrepareObjectForEditing = function(self)
--get the object and its profile table with the current values
local object = self:GetEditingObject()
@@ -243,56 +352,135 @@ detailsFramework.EditorMixin = {
local objectType = object:GetObjectType()
local attributeList
--get options and extra options
local editingOptions = self:GetEditingOptions()
local extraOptions = self:GetExtraOptions()
--get the attribute list for the object type
if (objectType == "FontString") then
---@cast object fontstring
attributeList = attributes[objectType]
end
--if there's extra options, add the attributeList to a new table and right after the extra options
if (extraOptions and #extraOptions > 0) then
local attributeListWithExtraOptions = {}
for i = 1, #attributeList do
attributeListWithExtraOptions[#attributeListWithExtraOptions+1] = attributeList[i]
end
attributeListWithExtraOptions[#attributeListWithExtraOptions+1] = {widget = "blank", default = true}
for i = 1, #extraOptions do
attributeListWithExtraOptions[#attributeListWithExtraOptions+1] = extraOptions[i]
end
attributeList = attributeListWithExtraOptions
end
local anchorSettings
--table to use on DF:BuildMenu()
local menuOptions = {}
for i = 1, #attributeList do
local option = attributeList[i]
--get the key to be used on profile table
local profileKey = profileMap[option.name]
local value
--if the key contains a dot or a bracket, it means it's a table path, example: "text_settings[1].width"
if (profileKey and (profileKey:match("%.") or profileKey:match("%["))) then
value = detailsFramework.table.getfrompath(profileTable, profileKey)
if (option.widget == "blank") then
menuOptions[#menuOptions+1] = {type = "blank"}
else
value = profileTable[profileKey]
end
--get the key to be used on profile table
local profileKey = profileMap[option.name]
local value
--if no value is found, attempt to get a default
value = value or option.default
--if the key contains a dot or a bracket, it means it's a table path, example: "text_settings[1].width"
if (profileKey and (profileKey:match("%.") or profileKey:match("%["))) then
value = detailsFramework.table.getfrompath(profileTable, profileKey)
else
value = profileTable[profileKey]
end
if (value) then
menuOptions[#menuOptions+1] = {
type = option.widget,
name = option.label,
get = function() return value end,
set = function(widget, fixedValue, newValue)
if (profileKey and (profileKey:match("%.") or profileKey:match("%["))) then
detailsFramework.table.setfrompath(profileTable, profileKey, value)
else
profileTable[profileKey] = value
end
--if no value is found, attempt to get a default
if (type(value) == "nil") then
value = option.default
end
if (self:GetOnEditCallback()) then
self:GetOnEditCallback()(object, option.name, newValue, profileTable, profileKey)
end
local bHasValue = type(value) ~= "nil"
if (option.name == "anchor" or option.name == "anchoroffsetx" or option.name == "anchoroffsety") then
local anchorTable = detailsFramework.table.getfrompath(profileTable, profileKey:gsub("%.[^.]*$", ""))
option.setter(object, anchorTable)
else
option.setter(object, newValue)
end
end,
min = option.minvalue,
max = option.maxvalue,
step = option.step,
usedecimals = option.usedecimals,
}
local minValue = option.minvalue
local maxValue = option.maxvalue
if (option.name == "anchoroffsetx") then
minValue = -object:GetParent():GetWidth()/2
maxValue = object:GetParent():GetWidth()/2
elseif (option.name == "anchoroffsety") then
minValue = -object:GetParent():GetHeight()/2
maxValue = object:GetParent():GetHeight()/2
end
if (option.name == "classcolor") then print("", value) end
if (bHasValue) then
if (option.name == "classcolor") then print("HERE", value) end
local parentTable = getParentTable(profileTable, profileKey)
if (option.name == "anchor" or option.name == "anchoroffsetx" or option.name == "anchoroffsety") then
anchorSettings = parentTable
end
menuOptions[#menuOptions+1] = {
type = option.widget,
name = option.label,
get = function() return value end,
set = function(widget, fixedValue, newValue, ...)
--color is a table with 4 indexes for each color plus alpha
if (option.widget == "color") then
--calor callback sends the red color in the fixedParameter slot
local r, g, b, alpha = fixedValue, newValue, ...
--need to use the same table from the profile table
parentTable[1] = r
parentTable[2] = g
parentTable[3] = b
parentTable[4] = alpha
newValue = parentTable
else
detailsFramework.table.setfrompath(profileTable, profileKey, newValue)
end
if (self:GetOnEditCallback()) then
self:GetOnEditCallback()(object, option.name, newValue, profileTable, profileKey)
end
--update the widget visual
--anchoring uses SetAnchor() which require the anchorTable to be passed
if (option.name == "anchor" or option.name == "anchoroffsetx" or option.name == "anchoroffsety") then
anchorSettings = parentTable
if (option.name == "anchor") then
anchorSettings.x = 0
anchorSettings.y = 0
end
self:StopObjectMovement()
option.setter(object, parentTable)
if (editingOptions.can_move) then
self:StartObjectMovement(anchorSettings)
end
else
option.setter(object, newValue)
end
end,
min = minValue,
max = maxValue,
step = option.step,
usedecimals = option.usedecimals,
id = option.name,
}
end
end
end
@@ -303,7 +491,9 @@ detailsFramework.EditorMixin = {
local optionsFrame = self:GetOptionsFrame()
local canvasScrollBox = self:GetCanvasScrollBox()
local bUseColon = true
local bUseColon = editingOptions.use_colon
local bSwitchIsCheckbox = true
local maxHeight = 5000
@@ -318,25 +508,361 @@ detailsFramework.EditorMixin = {
local options_slider_template = detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE")
local options_button_template = detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")
detailsFramework:BuildMenu(optionsFrame, menuOptions, 0, -2, maxHeight, bUseColon, options_text_template, options_dropdown_template, options_switch_template, bSwitchIsCheckbox, options_slider_template, options_button_template)
detailsFramework:BuildMenuVolatile(optionsFrame, menuOptions, 0, -2, maxHeight, bUseColon, options_text_template, options_dropdown_template, options_switch_template, bSwitchIsCheckbox, options_slider_template, options_button_template)
if (editingOptions.can_move) then
self:StartObjectMovement(anchorSettings)
end
end,
---@param self df_editor
---@param anchorSettings df_anchor
StartObjectMovement = function(self, anchorSettings)
local object = self:GetEditingObject()
local moverFrame = self:GetMoverFrame()
--self:UpdateGuideLinesAnchors()
--update guidelines
if (self:GetEditingOptions().use_guide_lines) then
--show all four guidelines
for side, texture in pairs(self.moverGuideLines) do
texture:Show()
end
end
local optionsFrame = self:GetOptionsFrame()
moverFrame:EnableMouse(true)
moverFrame:SetMovable(true)
moverFrame:ClearAllPoints()
moverFrame:Show()
--update the mover frame size to match the object size
if (object:GetObjectType() == "FontString") then
---@cast object fontstring
local width = object:GetStringWidth()
local height = object:GetStringHeight()
moverFrame:SetSize(width, height)
else
local width, height = object:GetSize()
moverFrame:SetSize(width, height)
end
for i = 1, object:GetNumPoints() do
local point, relativeTo, relativePoint, x, y = object:GetPoint(i)
moverFrame:SetPoint(point, relativeTo, relativePoint, x, y)
end
local currentPosX, currentPosY
moverFrame:SetScript("OnMouseDown", function()
object:ClearAllPoints()
object:SetPoint("topleft", moverFrame, "topleft", 0, 0)
currentPosX, currentPosY = moverFrame:GetCenter()
moverFrame:SetBackdropBorderColor(1, 1, 0, 0)
for i = 1, object:GetNumPoints() do
local point, relativeTo, relativePoint, x, y = object:GetPoint(i)
moverFrame:SetPoint(point, relativeTo, relativePoint, x, y)
end
moverFrame:StartMoving()
moverFrame.bIsMoving = true
end)
moverFrame:SetScript("OnMouseUp", function()
moverFrame:StopMovingOrSizing()
moverFrame.bIsMoving = false
object:ClearAllPoints()
detailsFramework:SetAnchor(object, anchorSettings, object:GetParent())
moverFrame:ClearAllPoints()
for i = 1, object:GetNumPoints() do
local point, relativeTo, relativePoint, x, y = object:GetPoint(i)
moverFrame:SetPoint(point, relativeTo, relativePoint, x, y)
end
end)
--detailsFramework:SetAnchor(moverFrame, anchorSettings)
--detailsFramework:SetAnchor(object, anchorSettings, moverFrame)
moverFrame:SetScript("OnUpdate", function()
--if the object isn't moving, make the mover follow the object position
if (moverFrame.bIsMoving) then
object:ClearAllPoints()
object:SetPoint("topleft", moverFrame, "topleft", 0, 0)
--if the object is moving, check if the moverFrame has moved
local newPosX, newPosY = moverFrame:GetCenter()
--did the frame moved?
if (newPosX ~= currentPosX) then
local xOffset = newPosX - currentPosX
anchorSettings.x = anchorSettings.x + xOffset
local anchorXSlider = optionsFrame:GetWidgetById("anchoroffsetx")
anchorXSlider:SetValueNoCallback(anchorSettings.x)
end
if (newPosY ~= currentPosY) then
local yOffset = newPosY - currentPosY
anchorSettings.y = anchorSettings.y + yOffset
local anchorYSlider = optionsFrame:GetWidgetById("anchoroffsety")
anchorYSlider:SetValueNoCallback(anchorSettings.y)
end
currentPosX, currentPosY = newPosX, newPosY
end
--[=[
--update the mover frame size to match the object size
if (object:GetObjectType() == "FontString") then
---@cast object fontstring
local width = object:GetStringWidth()
local height = object:GetStringHeight()
moverFrame:SetSize(width, height)
else
local width, height = object:GetSize()
moverFrame:SetSize(width, height)
end
--]=]
end)
end,
---@param self df_editor
StopObjectMovement = function(self)
local moverFrame = self:GetMoverFrame()
moverFrame:EnableMouse(false)
moverFrame:SetScript("OnUpdate", nil)
--hide all four guidelines
for side, texture in pairs(self.moverGuideLines) do
texture:Hide()
end
moverFrame:Hide()
end,
RegisterObject = function(self, object, localizedLabel, id, profileTable, profileKeyMap, extraOptions, callback, options)
assert(type(object) == "table", "RegisterObjectToEdit() expects an UIObject on #1 parameter.")
assert(object.GetObjectType, "RegisterObjectToEdit() expects an UIObject on #1 parameter.")
assert(type(profileTable) == "table", "RegisterObjectToEdit() expects a table on #4 parameter.")
assert(type(id) ~= "nil" and type(id) ~= "boolean", "RegisterObjectToEdit() expects an ID on parameter #3.")
assert(type(callback) == "function" or callback == nil, "RegisterObjectToEdit() expects a function or nil as the #7 parameter.")
local registeredObjects = self:GetAllRegisteredObjects()
--is object already registered?
for i = 1, #registeredObjects do
local objectRegistered = registeredObjects[i]
if (objectRegistered.object == object) then
error("RegisterObjectToEdit() object already registered.")
end
end
--deploy the options table
options = type(options) == "table" and options or {}
detailsFramework.table.deploy(options, editObjectDefaultOptions)
localizedLabel = type(localizedLabel) == "string" and localizedLabel or "invalid label"
---@type df_editor_objectinfo
local objectRegistered = {
object = object,
label = localizedLabel,
id = id,
profiletable = profileTable,
profilekeymap = profileKeyMap,
extraoptions = extraOptions or {},
callback = callback,
options = options,
}
registeredObjects[#registeredObjects+1] = objectRegistered
self.registeredObjectsByID[id] = objectRegistered
local objectSelector = self:GetObjectSelector()
objectSelector:RefreshMe()
--what to do after an object is registered?
return objectRegistered
end,
UnregisterObject = function(self, object)
local registeredObjects = self:GetAllRegisteredObjects()
for i = 1, #registeredObjects do
local objectRegistered = registeredObjects[i]
if (objectRegistered.object == object) then
self.registeredObjectsByID[objectRegistered.id] = nil
table.remove(registeredObjects, i)
break
end
end
local objectSelector = self:GetObjectSelector()
objectSelector:RefreshMe()
--stop editing the object
end,
---@param self df_editor
---@return df_editor_objectinfo[]
GetAllRegisteredObjects = function(self)
return self.registeredObjects
end,
---@param self df_editor
---@return df_editor_objectinfo?
GetObjectByRef = function(self, object)
local registeredObjects = self:GetAllRegisteredObjects()
for i = 1, #registeredObjects do
local objectRegistered = registeredObjects[i]
if (objectRegistered.object == object) then
return objectRegistered
end
end
end,
GetObjectByIndex = function(self, index)
local registeredObjects = self:GetAllRegisteredObjects()
return registeredObjects[index]
end,
GetObjectById = function(self, id)
return self.registeredObjectsByID[id]
end,
CreateObjectSelectionList = function(self, scroll_width, scroll_height, scroll_lines, scroll_line_height)
local editorFrame = self
local refreshFunc = function(self, data, offset, totalLines) --~refresh
for i = 1, totalLines do
local index = i + offset
---@type df_editor_objectinfo
local objectRegistered = data[index]
if (objectRegistered) then
local line = self:GetLine(i)
line.index = index
if (objectRegistered.object:GetObjectType() == "Texture") then
line.Icon:SetTexture([[Interface\AnimCreate\AnimCreateIcons]])
line.Icon:SetTexCoord(1/4, 2/4, 1/4, 2/4)
elseif (objectRegistered.object:GetObjectType() == "Texture") then
line.Icon:SetTexture([[Interface\AnimCreate\AnimCreateIcons]])
line.Icon:SetTexCoord(2/4, 3/4, 0, 1/4)
end
line.Label:SetText(objectRegistered.label)
end
end
end
local createLineFunc = function(self, index) -- ~createline --~line
local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate")
line:SetPoint("topleft", self, "topleft", 1, -((index-1)*(scroll_line_height+1)) - 1)
line:SetSize(scroll_width - 2, scroll_line_height)
line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
if (index % 2 == 0) then
line:SetBackdropColor(.1, .1, .1, .1)
else
line:SetBackdropColor(.1, .1, .1, .4)
end
detailsFramework:Mixin(line, detailsFramework.HeaderFunctions)
--line:SetScript("OnEnter", lineOnEnter)
--line:SetScript("OnLeave", lineOnLeave)
line:SetScript("OnClick", function(self)
local objectRegistered = editorFrame:GetObjectByIndex(self.index)
editorFrame:EditObject(objectRegistered)
end)
--icon
local objectIcon = line:CreateTexture("$parentIcon", "overlay")
objectIcon:SetSize(scroll_line_height - 2, scroll_line_height - 2)
--object label
local objectLabel = line:CreateFontString("$parentLabel", "overlay", "GameFontNormal")
objectIcon:SetPoint("left", line, "left", 2, 0)
objectLabel:SetPoint("left", objectIcon, "right", 2, 0)
line.Icon = objectIcon
line.Label = objectLabel
return line
end
local selectObjectScrollBox = detailsFramework:CreateScrollBox(self:GetParent(), "$parentSelectObjectScrollBox", refreshFunc, editorFrame:GetAllRegisteredObjects(), scroll_width, scroll_height, scroll_lines, scroll_line_height)
detailsFramework:ReskinSlider(selectObjectScrollBox)
function selectObjectScrollBox:RefreshMe()
selectObjectScrollBox:SetData(editorFrame:GetAllRegisteredObjects())
selectObjectScrollBox:Refresh()
end
--create lines
for i = 1, scroll_lines do
selectObjectScrollBox:CreateLine(createLineFunc)
end
return selectObjectScrollBox
end,
}
---@class df_editor_defaultoptions : table
---@field width number
---@field height number
---@field create_object_list boolean
---@field object_list_width number
---@field object_list_height number
---@field object_list_lines number
---@field object_list_line_height number
---@class df_editor_defaultoptions
local editorDefaultOptions = {
width = 400,
height = 600,
create_object_list = true,
object_list_width = 200,
object_list_height = 420,
object_list_lines = 20,
object_list_line_height = 20,
}
---@class df_editor : frame, df_optionsmixin, df_editormixin
---@field options table
---@field registeredObjects df_editor_objectinfo[]
---@field registeredObjectsByID table<any, df_editor_objectinfo>
---@field editingObject uiobject
---@field editingProfileTable table
---@field editingProfileMap table
---@field editingOptions df_editobjectoptions
---@field editingExtraOptions table
---@field moverGuideLines table<string, texture>
---@field onEditCallback function
---@field optionsFrame frame
---@field overTheTopFrame frame
---@field objectSelector df_scrollbox
---@field moverFrame frame
---@field canvasScrollBox df_canvasscrollbox
---@class df_editor_objectinfo : table
---@field object uiobject
---@field label string
---@field id any
---@field profiletable table
---@field profilekeymap table
---@field extraoptions table
---@field callback function
---@field options df_editobjectoptions
function detailsFramework:CreateEditor(parent, name, options)
name = name or ("DetailsFrameworkEditor" .. math.random(100000, 10000000))
local editorFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
@@ -344,10 +870,25 @@ function detailsFramework:CreateEditor(parent, name, options)
detailsFramework:Mixin(editorFrame, detailsFramework.EditorMixin)
detailsFramework:Mixin(editorFrame, detailsFramework.OptionsFunctions)
editorFrame.registeredObjects = {}
editorFrame.registeredObjectsByID = {}
editorFrame:BuildOptionsTable(editorDefaultOptions, options)
editorFrame:SetSize(editorFrame.options.width, editorFrame.options.height)
if (editorFrame.options.create_object_list) then
local scrollWidth = editorFrame.options.object_list_width
local scrollHeight = editorFrame.options.object_list_height
local scrollLinesAmount = editorFrame.options.object_list_lines
local scrollLineHeight = editorFrame.options.object_list_line_height
local objectSelector = editorFrame:CreateObjectSelectionList(scrollWidth, scrollHeight, scrollLinesAmount, scrollLineHeight)
objectSelector:SetPoint("topleft", editorFrame, "topright", 2, 0)
editorFrame.objectSelector = objectSelector
objectSelector:RefreshMe()
end
--options frame is the frame that holds the options for the editing object, it is used as the parent frame for BuildMenuVolatile()
local optionsFrame = CreateFrame("frame", name .. "OptionsFrame", editorFrame, "BackdropTemplate")
optionsFrame:SetSize(editorFrame.options.width, 5000)
@@ -355,6 +896,22 @@ function detailsFramework:CreateEditor(parent, name, options)
local canvasFrame = detailsFramework:CreateCanvasScrollBox(editorFrame, optionsFrame, name .. "CanvasScrollBox")
canvasFrame:SetAllPoints()
--over the top frame is a frame that is always on top of everything else
local OTTFrame = CreateFrame("frame", "$parentOTTFrame", UIParent)
OTTFrame:SetFrameStrata("TOOLTIP")
editorFrame.overTheTopFrame = OTTFrame
--frame that is used to move the object
local moverFrame = CreateFrame("frame", "$parentMoverFrame", OTTFrame, "BackdropTemplate")
moverFrame:SetClampedToScreen(true)
moverFrame:SetBackdrop({
edgeFile = "Interface\\Buttons\\WHITE8x8",
edgeSize = 1,
})
editorFrame.moverFrame = moverFrame
editorFrame:CreateMoverGuideLines()
editorFrame.optionsFrame = optionsFrame
editorFrame.canvasScrollBox = canvasFrame
+663
View File
@@ -0,0 +1,663 @@
---@class detailsframework
local detailsFramework = _G.DetailsFramework
if (not detailsFramework or not DetailsFrameworkCanLoad) then
return
end
local CreateFrame = CreateFrame
local defaultRed, defaultGreen, defaultBlue = detailsFramework:GetDefaultBackdropColor()
--local defaultColorTable = {defaultRed, defaultGreen, defaultBlue, 1}
local defaultColorTable = {0.98, 0.98, 0.98, 1}
local defaultBorderColorTable = {0.1, 0.1, 0.1, 1}
---@type edgenames[]
local cornerNames = {"TopLeft", "TopRight", "BottomLeft", "BottomRight"}
---@class blz_backdrop : table
---@field TopLeftCorner texture
---@field TopRightCorner texture
---@field BottomLeftCorner texture
---@field BottomRightCorner texture
---@field TopEdge texture
---@field BottomEdge texture
---@field LeftEdge texture
---@field RightEdge texture
---@field Center texture
---@class cornertextures : table
---@field TopLeft texture
---@field TopRight texture
---@field BottomLeft texture
---@field BottomRight texture
---@class edgetextures : table
---@field Top texture
---@field Bottom texture
---@field Left texture
---@field Right texture
---@class df_roundedpanel_options : table
---@field width number
---@field height number
---@field use_titlebar boolean
---@field use_scalebar boolean
---@field title string
---@field scale number
---@field roundness number
---@field color any
---@field border_color any
---@field corner_texture texturepath|textureid
---@field horizontal_border_size_offset number?
---@class df_roundedpanel_preset : table, df_roundedpanel_options
---@field border_color any
---@field color any
---@field roundness number
---@class df_roundedcornermixin : table
---@field RoundedCornerConstructor fun(self:df_roundedpanel) --called from CreateRoundedPanel
---@field SetColor fun(self:df_roundedpanel, red: any, green: number|nil, blue: number|nil, alpha: number|nil)
---@field SetBorderCornerColor fun(self:df_roundedpanel, red: any, green: number|nil, blue: number|nil, alpha: number|nil)
---@field SetRoundness fun(self:df_roundedpanel, slope: number)
---@field GetCornerSize fun(self:df_roundedpanel) : width, height
---@field OnSizeChanged fun(self:df_roundedpanel) --called when the frame size changes
---@field CreateBorder fun(self:df_roundedpanel) --called from SetBorderCornerColor if the border is not created yet
---@field CalculateBorderEdgeSize fun(self:df_roundedpanel, alignment: "vertical"|"horizontal"): number --calculate the size of the border edge texture
---@field SetTitleBarColor fun(self:df_roundedpanel, red: any, green: number|nil, blue: number|nil, alpha: number|nil)
---@field GetMaxFrameLevel fun(self:df_roundedpanel) : number --return the max frame level of the frame and its children
---@class df_roundedpanel : frame, df_roundedcornermixin, df_optionsmixin, df_titlebar
---@field bHasBorder boolean
---@field bHasTitleBar boolean
---@field options df_roundedpanel_options
---@field cornerRoundness number
---@field CornerTextures cornertextures
---@field CenterTextures texture[]
---@field BorderCornerTextures cornertextures
---@field BorderEdgeTextures edgetextures
---@field TitleBar df_roundedpanel
---@field bIsTitleBar boolean
---@field TopLeft texture corner texture
---@field TopRight texture corner texture
---@field BottomLeft texture corner texture
---@field BottomRight texture corner texture
---@field TopEdgeBorder texture border edge
---@field BottomEdgeBorder texture border edge
---@field LeftEdgeBorder texture border edge
---@field RightEdgeBorder texture border edge
---@field TopLeftBorder texture border corner
---@field TopRightBorder texture border corner
---@field BottomLeftBorder texture border corner
---@field BottomRightBorder texture border corner
---@field TopHorizontalEdge texture texture connecting the top corners
---@field BottomHorizontalEdge texture texture connecting the bottom corners
---@field CenterBlock texture texture connecting the bottom left of the topleft corner with the top right of the bottom right corner
---@param self df_roundedpanel
---@param textures cornertextures
---@param width number|nil
---@param height number|nil
---@param xOffset number|nil
---@param yOffset number|nil
---@param bIsBorder boolean|nil
local setCornerPoints = function(self, textures, width, height, xOffset, yOffset, bIsBorder)
for cornerName, thisTexture in pairs(textures) do
thisTexture:SetSize(width or 16, height or 16)
thisTexture:SetTexture(self.options.corner_texture)
--set the mask
if (not thisTexture.MaskTexture and bIsBorder) then
thisTexture.MaskTexture = self:CreateMaskTexture(nil, "background")
thisTexture.MaskTexture:SetSize(74, 64)
thisTexture:AddMaskTexture(thisTexture.MaskTexture)
thisTexture.MaskTexture:SetTexture([[Interface\Azerite\AzeriteGoldRingRank2]]) --1940690
--thisTexture.MaskTexture:Hide()
end
xOffset = xOffset or 0
yOffset = yOffset or 0
--todo: adjust the other corners setpoint offset
--todo (done): use mask when the alpha is below 0.98, disable the mask when the alpha is above 0.98
if (cornerName == "TopLeft") then
thisTexture:SetTexCoord(0, 0.5, 0, 0.5)
thisTexture:SetPoint(cornerName, self, cornerName, -xOffset, yOffset)
if (thisTexture.MaskTexture) then
thisTexture.MaskTexture:SetPoint(cornerName, self, cornerName, -18-xOffset, 16+yOffset)
end
elseif (cornerName == "TopRight") then
thisTexture:SetTexCoord(0.5, 1, 0, 0.5)
thisTexture:SetPoint(cornerName, self, cornerName, xOffset, yOffset)
if (thisTexture.MaskTexture) then
thisTexture.MaskTexture:SetPoint(cornerName, self, cornerName, -18+xOffset, 16+yOffset)
end
elseif (cornerName == "BottomLeft") then
thisTexture:SetTexCoord(0, 0.5, 0.5, 1)
thisTexture:SetPoint(cornerName, self, cornerName, -xOffset, -yOffset)
if (thisTexture.MaskTexture) then
thisTexture.MaskTexture:SetPoint(cornerName, self, cornerName, -18-xOffset, 16-yOffset)
end
elseif (cornerName == "BottomRight") then
thisTexture:SetTexCoord(0.5, 1, 0.5, 1)
thisTexture:SetPoint(cornerName, self, cornerName, xOffset, -yOffset)
if (thisTexture.MaskTexture) then
thisTexture.MaskTexture:SetPoint(cornerName, self, cornerName, -18+xOffset, 16-yOffset)
end
end
end
end
detailsFramework.RoundedCornerPanelMixin = {
RoundedCornerConstructor = function(self)
self.CornerTextures = {}
self.CenterTextures = {}
self.BorderCornerTextures = {}
self.BorderEdgeTextures = {}
self.cornerRoundness = 0
for i = 1, #cornerNames do
---@type texture
local newCornerTexture = self:CreateTexture(nil, "border", nil, 0)
self.CornerTextures[cornerNames[i]] = newCornerTexture
self[cornerNames[i]] = newCornerTexture
end
--create the top texture which connects the top corners with a horizontal line
---@type texture
local topHorizontalEdge = self:CreateTexture(nil, "border", nil, 0)
topHorizontalEdge:SetPoint("topleft", self.CornerTextures["TopLeft"], "topright", 0, 0)
topHorizontalEdge:SetPoint("bottomleft", self.CornerTextures["TopLeft"], "bottomright", 0, 0)
topHorizontalEdge:SetPoint("topright", self.CornerTextures["TopRight"], "topleft", 0, 0)
topHorizontalEdge:SetPoint("bottomright", self.CornerTextures["TopRight"], "bottomleft", 0, 0)
topHorizontalEdge:SetColorTexture(unpack(defaultColorTable))
--create the bottom texture which connects the bottom corners with a horizontal line
---@type texture
local bottomHorizontalEdge = self:CreateTexture(nil, "border", nil, 0)
bottomHorizontalEdge:SetPoint("topleft", self.CornerTextures["BottomLeft"], "topright", 0, 0)
bottomHorizontalEdge:SetPoint("bottomleft", self.CornerTextures["BottomLeft"], "bottomright", 0, 0)
bottomHorizontalEdge:SetPoint("topright", self.CornerTextures["BottomRight"], "topleft", 0, 0)
bottomHorizontalEdge:SetPoint("bottomright", self.CornerTextures["BottomRight"], "bottomleft", 0, 0)
bottomHorizontalEdge:SetColorTexture(unpack(defaultColorTable))
--create the center block which connects the bottom left of the topleft corner with the top right of the bottom right corner
---@type texture
local centerBlock = self:CreateTexture(nil, "border", nil, 0)
centerBlock:SetPoint("topleft", self.CornerTextures["TopLeft"], "bottomleft", 0, 0)
centerBlock:SetPoint("bottomleft", self.CornerTextures["BottomLeft"], "topleft", 0, 0)
centerBlock:SetPoint("topright", self.CornerTextures["BottomRight"], "topright", 0, 0)
centerBlock:SetPoint("bottomright", self.CornerTextures["BottomRight"], "topright", 0, 0)
centerBlock:SetColorTexture(unpack(defaultColorTable))
self.CenterTextures[#self.CenterTextures+1] = topHorizontalEdge
self.CenterTextures[#self.CenterTextures+1] = bottomHorizontalEdge
self.CenterTextures[#self.CenterTextures+1] = centerBlock
self.TopHorizontalEdge = topHorizontalEdge
self.BottomHorizontalEdge = bottomHorizontalEdge
self.CenterBlock = centerBlock
---@type width
local width = self.options.width
---@type height
local height = self.options.height
self:SetSize(width, height)
--fill the corner and edge textures table
setCornerPoints(self, self.CornerTextures)
end,
---get the highest frame level of the rounded panel and its children
---@param self df_roundedpanel
---@return framelevel
GetMaxFrameLevel = function(self)
---@type framelevel
local maxFrameLevel = 0
local children = {self:GetChildren()}
for i = 1, #children do
local thisChild = children[i]
---@cast thisChild frame
if (thisChild:GetFrameLevel() > maxFrameLevel) then
maxFrameLevel = thisChild:GetFrameLevel()
end
end
return maxFrameLevel
end,
---create a frame placed at the top side of the rounded panel, this frame has a member called 'Text' which is a fontstring for the title
---@param self df_roundedpanel
---@return df_roundedpanel
CreateTitleBar = function(self)
---@type df_roundedpanel
local titleBar = detailsFramework:CreateRoundedPanel(self, "$parentTitleBar", {width = self.options.width - 6, height = 16})
titleBar:SetPoint("top", self, "top", 0, -4)
titleBar:SetRoundness(5)
titleBar:SetFrameLevel(9500)
titleBar.bIsTitleBar = true
self.TitleBar = titleBar
self.bHasTitleBar = true
local textFontString = titleBar:CreateFontString("$parentText", "overlay", "GameFontNormal")
textFontString:SetPoint("center", titleBar, "center", 0, 0)
titleBar.Text = textFontString
local closeButton = detailsFramework:CreateCloseButton(titleBar, "$parentCloseButton")
closeButton:SetPoint("right", titleBar, "right", -3, 0)
closeButton:SetSize(10, 10)
closeButton:SetAlpha(0.3)
closeButton:SetScript("OnClick", function(self)
self:GetParent():GetParent():Hide()
end)
detailsFramework:SetButtonTexture(closeButton, "common-search-clearbutton")
return titleBar
end,
---return the width and height of the corner textures
---@param self df_roundedpanel
---@return number, number
GetCornerSize = function(self)
return self.CornerTextures["TopLeft"]:GetSize()
end,
---set how rounded the corners should be
---@param self df_roundedpanel
---@param roundness number
SetRoundness = function(self, roundness)
self.cornerRoundness = roundness
self:OnSizeChanged()
end,
---adjust the size of the corner textures and the border edge textures
---@param self df_roundedpanel
OnSizeChanged = function(self)
--if the frame has a titlebar, need to adjust the size of the titlebar
if (self.bHasTitleBar) then
self.TitleBar:SetWidth(self:GetWidth() - 14)
end
--if the frame height is below 32, need to recalculate the size of the corners
---@type height
local frameHeight = self:GetHeight()
if (frameHeight < 32) then
local newCornerSize = frameHeight / 2
--set the new size of the corners on all corner textures
for _, thisTexture in pairs(self.CornerTextures) do
thisTexture:SetSize(newCornerSize - (self.cornerRoundness - 2), newCornerSize)
end
--check if the frame has border and set the size of the border corners as well
if (self.bHasBorder) then
for _, thisTexture in pairs(self.BorderCornerTextures) do
thisTexture:SetSize(newCornerSize-2, newCornerSize+2)
end
--hide the left and right edges as the corner textures already is enough to fill the frame
self.BorderEdgeTextures["Left"]:Hide()
self.BorderEdgeTextures["Right"]:Hide()
local horizontalEdgesNewSize = self:CalculateBorderEdgeSize("horizontal")
self.BorderEdgeTextures["Top"]:SetSize(horizontalEdgesNewSize + (self.options.horizontal_border_size_offset or 0), 1)
self.BorderEdgeTextures["Bottom"]:SetSize(horizontalEdgesNewSize + (self.options.horizontal_border_size_offset or 0), 1)
end
self.CenterBlock:Hide()
else
if (self.bHasBorder) then
self.BorderEdgeTextures["Left"]:Show()
self.BorderEdgeTextures["Right"]:Show()
end
---@type width, height
local cornerWidth, cornerHeight = 16, 16
self.CenterBlock:Show()
for _, thisTexture in pairs(self.CornerTextures) do
thisTexture:SetSize(cornerWidth-self.cornerRoundness, cornerHeight-self.cornerRoundness)
end
if (self.bHasBorder) then
for _, thisTexture in pairs(self.BorderCornerTextures) do
thisTexture:SetSize(cornerWidth-self.cornerRoundness, cornerHeight-self.cornerRoundness)
thisTexture.MaskTexture:SetSize(74-(self.cornerRoundness*0.75), 64-self.cornerRoundness)
end
local horizontalEdgesNewSize = self:CalculateBorderEdgeSize("horizontal")
self.BorderEdgeTextures["Top"]:SetSize(horizontalEdgesNewSize, 1)
self.BorderEdgeTextures["Bottom"]:SetSize(horizontalEdgesNewSize, 1)
local verticalEdgesNewSize = self:CalculateBorderEdgeSize("vertical")
self.BorderEdgeTextures["Left"]:SetSize(1, verticalEdgesNewSize)
self.BorderEdgeTextures["Right"]:SetSize(1, verticalEdgesNewSize)
end
end
end,
---get the size of the edge texture
---@param self df_roundedpanel
---@param alignment "vertical"|"horizontal"
---@return number edgeSize
CalculateBorderEdgeSize = function(self, alignment)
---@type string
local borderCornerName = next(self.BorderCornerTextures)
if (not borderCornerName) then
return 0
end
---@type texture
local borderTexture = self.BorderCornerTextures[borderCornerName]
alignment = alignment:lower()
if (alignment == "vertical") then
return self:GetHeight() - (borderTexture:GetHeight() * 2) + 2
elseif (alignment == "horizontal") then
return self:GetWidth() - (borderTexture:GetHeight() * 2) + 2
end
error("df_roundedpanel:CalculateBorderEdgeSize(self, alignment) alignment must be 'vertical' or 'horizontal'")
end,
---@param self df_roundedpanel
CreateBorder = function(self)
local r, g, b, a = 0, 0, 0, 0.8
--create the corner edges
for i = 1, #cornerNames do
---@type texture
local newBorderTexture = self:CreateTexture(nil, "background", nil, 0)
self.BorderCornerTextures[cornerNames[i]] = newBorderTexture
newBorderTexture:SetColorTexture(unpack(defaultColorTable))
newBorderTexture:SetVertexColor(r, g, b, a)
self[cornerNames[i] .. "Border"] = newBorderTexture
end
setCornerPoints(self, self.BorderCornerTextures, 16, 16, 1, 1, true)
--create the top, left, bottom and right edges, the edge has 1pixel width and connects the corners
---@type texture
local topEdge = self:CreateTexture(nil, "background", nil, 0)
topEdge:SetPoint("bottom", self, "top", 0, 0)
self.BorderEdgeTextures["Top"] = topEdge
---@type texture
local leftEdge = self:CreateTexture(nil, "background", nil, 0)
leftEdge:SetPoint("right", self, "left", 0, 0)
self.BorderEdgeTextures["Left"] = leftEdge
---@type texture
local bottomEdge = self:CreateTexture(nil, "background", nil, 0)
bottomEdge:SetPoint("top", self, "bottom", 0, 0)
self.BorderEdgeTextures["Bottom"] = bottomEdge
---@type texture
local rightEdge = self:CreateTexture(nil, "background", nil, 0)
rightEdge:SetPoint("left", self, "right", 0, 0)
self.BorderEdgeTextures["Right"] = rightEdge
---@type width
local horizontalEdgeSize = self:CalculateBorderEdgeSize("horizontal")
---@type height
local verticalEdgeSize = self:CalculateBorderEdgeSize("vertical")
--set the edges size
topEdge:SetSize(horizontalEdgeSize, 1)
leftEdge:SetSize(1, verticalEdgeSize)
bottomEdge:SetSize(horizontalEdgeSize, 1)
rightEdge:SetSize(1, verticalEdgeSize)
for edgeName, thisTexture in pairs(self.BorderEdgeTextures) do
---@cast thisTexture texture
thisTexture:SetColorTexture(unpack(defaultColorTable))
thisTexture:SetVertexColor(r, g, b, a)
end
self.TopEdgeBorder = topEdge
self.BottomEdgeBorder = bottomEdge
self.LeftEdgeBorder = leftEdge
self.RightEdgeBorder = rightEdge
self.bHasBorder = true
end,
---@param self df_roundedpanel
---@param red any
---@param green number|nil
---@param blue number|nil
---@param alpha number|nil
SetTitleBarColor = function(self, red, green, blue, alpha)
if (self.bHasTitleBar) then
red, green, blue, alpha = detailsFramework:ParseColors(red, green, blue, alpha)
self.TitleBar:SetColor(red, green, blue, alpha)
end
end,
---@param self df_roundedpanel
---@param red any
---@param green number|nil
---@param blue number|nil
---@param alpha number|nil
SetBorderCornerColor = function(self, red, green, blue, alpha)
if (not self.bHasBorder) then
self:CreateBorder()
end
red, green, blue, alpha = detailsFramework:ParseColors(red, green, blue, alpha)
for _, thisTexture in pairs(self.BorderCornerTextures) do
thisTexture:SetVertexColor(red, green, blue, alpha)
end
for _, thisTexture in pairs(self.BorderEdgeTextures) do
thisTexture:SetVertexColor(red, green, blue, alpha)
end
end,
---@param self df_roundedpanel
---@param red any
---@param green number|nil
---@param blue number|nil
---@param alpha number|nil
SetColor = function(self, red, green, blue, alpha)
red, green, blue, alpha = detailsFramework:ParseColors(red, green, blue, alpha)
for _, thisTexture in pairs(self.CornerTextures) do
thisTexture:SetVertexColor(red, green, blue, alpha)
end
for _, thisTexture in pairs(self.CenterTextures) do
thisTexture:SetVertexColor(red, green, blue, alpha)
end
if (self.bHasBorder) then
if (alpha < 0.98) then
--if using borders, the two border textures overlaps making the alpha be darker than it should
for _, thisTexture in pairs(self.BorderCornerTextures) do
thisTexture.MaskTexture:Show()
end
else
for _, thisTexture in pairs(self.BorderCornerTextures) do
thisTexture.MaskTexture:Hide()
end
end
end
end,
}
local defaultOptions = {
width = 200,
height = 200,
use_titlebar = false,
use_scalebar = false,
title = "",
scale = 1,
roundness = 0,
color = defaultColorTable,
border_color = defaultColorTable,
corner_texture = [[Interface\CHARACTERFRAME\TempPortraitAlphaMaskSmall]],
}
local defaultPreset = {
border_color = {.1, .1, .1, 0.834},
color = {defaultRed, defaultGreen, defaultBlue},
roundness = 3,
}
---create a regular panel with rounded corner
---@param parent frame
---@param name string|nil
---@param optionsTable table|nil
---@return df_roundedpanel
function detailsFramework:CreateRoundedPanel(parent, name, optionsTable)
---@type df_roundedpanel
local newRoundedPanel = CreateFrame("frame", name, parent, "BackdropTemplate")
newRoundedPanel:EnableMouse(true)
newRoundedPanel.__dftype = "df_roundedpanel"
newRoundedPanel.__rcorners = true
detailsFramework:Mixin(newRoundedPanel, detailsFramework.RoundedCornerPanelMixin)
detailsFramework:Mixin(newRoundedPanel, detailsFramework.OptionsFunctions)
newRoundedPanel:BuildOptionsTable(defaultOptions, optionsTable or {})
newRoundedPanel:RoundedCornerConstructor()
newRoundedPanel:SetScript("OnSizeChanged", newRoundedPanel.OnSizeChanged)
if (newRoundedPanel.options.use_titlebar) then
---@type df_roundedpanel
local titleBar = detailsFramework:CreateRoundedPanel(newRoundedPanel, "$parentTitleBar", {height = 26})
titleBar:SetPoint("top", newRoundedPanel, "top", 0, -7)
newRoundedPanel.TitleBar = titleBar
titleBar:SetRoundness(5)
newRoundedPanel.bHasTitleBar = true
end
if (newRoundedPanel.options.use_scalebar) then
detailsFramework:CreateScaleBar(newRoundedPanel.TitleBar or newRoundedPanel, newRoundedPanel.options)
newRoundedPanel:SetScale(newRoundedPanel.options.scale)
end
newRoundedPanel:SetRoundness(newRoundedPanel.options.roundness)
newRoundedPanel:SetColor(newRoundedPanel.options.color)
newRoundedPanel:SetBorderCornerColor(newRoundedPanel.options.border_color)
return newRoundedPanel
end
local applyPreset = function(frame, preset)
if (preset.border_color) then
frame:SetBorderCornerColor(preset.border_color)
end
if (preset.color) then
frame:SetColor(preset.color)
end
if (preset.roundness) then
frame:SetRoundness(preset.roundness)
else
frame:SetRoundness(1)
end
if (preset.use_titlebar) then
frame:CreateTitleBar()
end
end
---set a frame to have rounded corners following the settings passed by the preset table
---@param frame frame
---@param preset df_roundedpanel_preset?
function detailsFramework:AddRoundedCornersToFrame(frame, preset)
frame = frame and frame.widget or frame
assert(frame and frame.GetObjectType and frame.SetPoint, "AddRoundedCornersToFrame(frame): frame must be a frame object.")
if (frame.__rcorners) then
return
end
if (frame.GetBackdropBorderColor) then
local red, green, blue, alpha = frame:GetBackdropBorderColor()
if (alpha and alpha > 0) then
detailsFramework:MsgWarning("AddRoundedCornersToFrame() applyed to a frame with a backdrop border.")
detailsFramework:Msg(debugstack(2, 1, 0))
end
end
---@cast frame +df_roundedcornermixin
detailsFramework:Mixin(frame, detailsFramework.RoundedCornerPanelMixin)
if (not frame["BuildOptionsTable"]) then
---@cast frame +df_optionsmixin
detailsFramework:Mixin(frame, detailsFramework.OptionsFunctions)
end
frame:BuildOptionsTable(defaultOptions, {})
frame.options.width = frame:GetWidth()
frame.options.height = frame:GetHeight()
frame:RoundedCornerConstructor()
frame:HookScript("OnSizeChanged", frame.OnSizeChanged)
frame.__rcorners = true
--handle preset
if (preset and type(preset) == "table") then
frame.options.horizontal_border_size_offset = preset.horizontal_border_size_offset
applyPreset(frame, preset)
else
applyPreset(frame, defaultPreset)
end
end
---test case:
C_Timer.After(1, function()
if true then return end
local DF = DetailsFramework
local parent = UIParent
local name = "NewRoundedCornerFrame"
local optionsTable = {
use_titlebar = true,
use_scalebar = true,
title = "Test",
scale = 1.0,
}
---@type df_roundedpanel
local frame = _G[name] or DF:CreateRoundedPanel(parent, name, optionsTable)
frame:SetSize(800, 600)
frame:SetPoint("center", parent, "center", 0, 0)
frame:SetColor(.1, .1, .1, 1)
frame:SetTitleBarColor(.2, .2, .2, .5)
frame:SetBorderCornerColor(.2, .2, .2, .5)
frame:SetRoundness(0)
local radiusSlider = DF:CreateSlider(frame, 120, 14, 0, 15, 1, frame.cornerRoundness, false, "RadiusBar", nil, nil, DF:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE"))
radiusSlider:SetHook("OnValueChange", function(self, fixedValue, value)
value = floor(value)
if (frame.cornerRoundness == value) then
return
end
frame:SetRoundness(value)
end)
local radiusText = frame:CreateFontString(nil, "overlay", "GameFontNormal")
radiusText:SetText("Radius:")
radiusText:SetPoint("bottomleft", radiusSlider.widget, "topleft", 0, 0)
radiusSlider:SetPoint(10, -100)
end)
+14 -65
View File
@@ -1,6 +1,6 @@
local dversion = 482
local dversion = 484
local major, minor = "DetailsFramework-1.0", dversion
local DF, oldminor = LibStub:NewLibrary(major, minor)
@@ -49,6 +49,8 @@ function DF:MsgWarning(msg, ...)
print("|cFFFFFFAA" .. (self.__name or "Details!Framework") .. "|r |cFFFFAA00[Warning]|r", msg, ...)
end
DF.internalFunctions = DF.internalFunctions or {}
local PixelUtil = PixelUtil or DFPixelUtil
if (not PixelUtil) then
--check if is in classic, TBC, or WotLK wow, if it is, build a replacement for PixelUtil
@@ -514,6 +516,8 @@ function DF.table.getfrompath(t, path)
end
return value
else
return t[path] or t[tonumber(path)]
end
end
@@ -539,7 +543,12 @@ function DF.table.setfrompath(t, path, value)
lastTable[lastKey] = value
return true
end
else
t[path] = value
return true
end
return false
end
---find the value inside the table, and it it's not found, add it
@@ -1888,7 +1897,7 @@ local anchoringFunctions = {
---set the anchor point using a df_anchor table
---@param widget uiobject
---@param anchorTable df_anchor
---@param anchorTo uiobject
---@param anchorTo uiobject?
function DF:SetAnchor(widget, anchorTable, anchorTo)
anchorTo = anchorTo or widget:GetParent()
anchoringFunctions[anchorTable.side](widget, anchorTo, anchorTable.x, anchorTable.y)
@@ -2093,67 +2102,6 @@ end
TutorialAlertFrame:Show()
end
local refresh_options = function(self)
for _, widget in ipairs(self.widget_list) do
if (widget._get) then
if (widget.widget_type == "label") then
if (widget._get() and not widget.languageAddonId) then
widget:SetText(widget._get())
end
elseif (widget.widget_type == "select") then
widget:Select(widget._get())
elseif (widget.widget_type == "toggle" or widget.widget_type == "range") then
widget:SetValue(widget._get())
elseif (widget.widget_type == "textentry") then
widget:SetText(widget._get())
elseif (widget.widget_type == "color") then
local default_value, g, b, a = widget._get()
if (type(default_value) == "table") then
widget:SetColor (unpack(default_value))
else
widget:SetColor (default_value, g, b, a)
end
end
end
end
end
local get_frame_by_id = function(self, id)
return self.widgetids [id]
end
function DF:ClearOptionsPanel(frame)
for i = 1, #frame.widget_list do
frame.widget_list[i]:Hide()
if (frame.widget_list[i].hasLabel) then
frame.widget_list[i].hasLabel:SetText("")
end
end
table.wipe(frame.widgetids)
end
function DF:SetAsOptionsPanel(frame)
frame.RefreshOptions = refresh_options
frame.widget_list = {}
frame.widget_list_by_type = {
["dropdown"] = {}, -- "select"
["switch"] = {}, -- "toggle"
["slider"] = {}, -- "range"
["color"] = {}, --
["button"] = {}, -- "execute"
["textentry"] = {}, --
["label"] = {}, --"text"
}
frame.widgetids = {}
frame.GetWidgetById = get_frame_by_id
end
function DF:CreateOptionsFrame(name, title, template)
template = template or 1
@@ -2162,7 +2110,7 @@ end
tinsert(UISpecialFrames, name)
newOptionsFrame:SetSize(500, 200)
newOptionsFrame.RefreshOptions = refresh_options
newOptionsFrame.RefreshOptions = DF.internalFunctions.RefreshOptionsPanel
newOptionsFrame.widget_list = {}
newOptionsFrame:SetScript("OnMouseDown", function(self, button)
@@ -2200,7 +2148,7 @@ end
tinsert(UISpecialFrames, name)
newOptionsFrame:SetSize(500, 200)
newOptionsFrame.RefreshOptions = refresh_options
newOptionsFrame.RefreshOptions = DF.internalFunctions.RefreshOptionsPanel
newOptionsFrame.widget_list = {}
newOptionsFrame:SetScript("OnMouseDown", function(self, button)
@@ -2703,6 +2651,7 @@ function DF:CreateAnimation(animation, animationType, order, duration, arg1, arg
elseif (animationType == "ROTATION") then
anim:SetDegrees(arg1) --degree
--print("SetOrigin", arg2, arg3, arg4)
anim:SetOrigin(arg2 or "center", arg3 or 0, arg4 or 0) --point, x, y
elseif (animationType == "TRANSLATION") then
+11
View File
@@ -706,6 +706,17 @@ local canvasScrollBoxDefaultOptions = {
function detailsFramework:CreateCanvasScrollBox(parent, child, name, options)
---@type df_canvasscrollbox
local canvasScrollBox = CreateFrame("scrollframe", name or ("DetailsFrameworkCanvasScroll" .. math.random(50000, 10000000)), parent, "BackdropTemplate, UIPanelScrollFrameTemplate")
canvasScrollBox.scrollStep = 20
canvasScrollBox:SetScript("OnMouseWheel", function(self, value)
local scrollBar = self
local scrollStep = scrollBar.scrollStep or scrollBar:GetHeight() / 2
if ( value > 0 ) then
scrollBar:SetVerticalScroll(scrollBar:GetVerticalScroll() - scrollStep)
else
scrollBar:SetVerticalScroll(scrollBar:GetVerticalScroll() + scrollStep)
end
end)
detailsFramework:Mixin(canvasScrollBox, detailsFramework.CanvasScrollBoxMixin)
detailsFramework:Mixin(canvasScrollBox, detailsFramework.OptionsFunctions)
+17 -11
View File
@@ -232,6 +232,11 @@ DF:Mixin(DFSliderMetaFunctions, DF.ScriptHookMixin)
return self(value)
end
function DFSliderMetaFunctions:SetValueNoCallback(value)
self.NoCallback = true
self.slider:SetValue(value)
end
-- thumb size
function DFSliderMetaFunctions:SetThumbSize(width, height)
if (not width) then
@@ -697,6 +702,18 @@ DF:Mixin(DFSliderMetaFunctions, DF.ScriptHookMixin)
table.insert(object.previous_value, 1, amt)
table.remove(object.previous_value, 4)
if (object.useDecimals) then
slider.amt:SetText(string.format("%.2f", amt))
else
slider.amt:SetText(math.floor(amt))
end
object.ivalue = amt
if (object.NoCallback) then
object.NoCallback = false
return
end
--some plugins registered OnValueChanged and others with OnValueChange
local kill = object:RunHooksForWidget("OnValueChanged", slider, object.FixedValue, amt, object)
if (kill) then
@@ -711,17 +728,6 @@ DF:Mixin(DFSliderMetaFunctions, DF.ScriptHookMixin)
if (object.OnValueChanged) then
object.OnValueChanged(slider, object.FixedValue, amt)
end
if (amt < 10 and amt >= 1) then
amt = "0" .. amt
end
if (object.useDecimals) then
slider.amt:SetText(string.format("%.2f", amt))
else
slider.amt:SetText(math.floor(amt))
end
object.ivalue = amt
end
------------------------------------------------------------------------------------------------------------
+13 -2
View File
@@ -271,6 +271,8 @@ function detailsFramework:CreateTabContainer(parent, title, frameName, tabList,
local buttonTextSize = optionsTable.button_text_size or 10
local containerWidthOffset = optionsTable.container_width_offset or 0
local bFirstTabIsCreateOnDemand = false
--create the base frame
---@type df_tabcontainer
local tabContainer = CreateFrame("frame", frameName, parent["widget"] or parent, "BackdropTemplate")
@@ -318,10 +320,14 @@ function detailsFramework:CreateTabContainer(parent, title, frameName, tabList,
if (tabInfo.createOnDemandFunc) then
tabFrame:SetScript("OnShow", function()
if (tabInfo.createOnDemandFunc) then
detailsFramework:Dispatch(tabInfo.createOnDemandFunc, tabFrame, parent)
detailsFramework:Dispatch(tabInfo.createOnDemandFunc, tabFrame, tabContainer, parent)
tabInfo.createOnDemandFunc = nil
end
end)
if (tabIndex == 1) then
bFirstTabIsCreateOnDemand = true
end
end
--attempt to get the localized text from the language system using the addonId and the frameInfo.text
@@ -405,7 +411,12 @@ function detailsFramework:CreateTabContainer(parent, title, frameName, tabList,
tabContainer:SetScript("OnShow", tabContainer.OnShow)
--select the first frame
local defaultTab = 1
tabContainer:SelectTabByIndex(defaultTab)
if (bFirstTabIsCreateOnDemand) then
C_Timer.After(0, function() tabContainer:SelectTabByIndex(defaultTab) end)
else
tabContainer:SelectTabByIndex(defaultTab)
end
return tabContainer
end
+1
View File
@@ -1937,6 +1937,7 @@ function detailsFramework:CreateCastBar(parent, name, settingsOverride)
detailsFramework:Mixin(castBar, detailsFramework.CastFrameFunctions)
detailsFramework:Mixin(castBar, detailsFramework.StatusBarFunctions)
castBar:CreateTextureMask()
castBar:AddMaskTexture(castBar.flashTexture)
castBar:AddMaskTexture(castBar.background)
+1 -1
View File
@@ -39,7 +39,7 @@ if (WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE and not isExpansion_Dragonflight()) t
end
local major = "LibOpenRaid-1.0"
local CONST_LIB_VERSION = 113
local CONST_LIB_VERSION = 114
if (LIB_OPEN_RAID_MAX_VERSION) then
if (CONST_LIB_VERSION <= LIB_OPEN_RAID_MAX_VERSION) then
@@ -547,7 +547,10 @@ do
[5384] = {cooldown = 30, duration = 0, specs = {}, talent = false, charges = 1, class = "HUNTER", type = 5}, --Feign Death
[186387] = {cooldown = 30, duration = 6, specs = {}, talent = false, charges = 1, class = "HUNTER", type = 8}, --Bursting Shot
[236776] = {cooldown = 40, duration = 0, specs = {253, 254, 255}, talent = false, charges = 1, class = "HUNTER", type = 8}, --High Explosive Trap
[272682] = {cooldown = 45, duration = 4, specs = {253, 254, 255}, talent = false, charges = 1, class = "HUNTER", type = 7}, --Master's Call
--Boar nil 62305 Master's Call
--Boar Tiranaa 54216 Master's Call
--Tiranaa Tiranaa 272682 Master's Call
--~druid
-- 102 - Balance
+4
View File
@@ -416,6 +416,10 @@
end
end
function classCombat:GetRunTime()
return self.run_time or self:GetCombatTime()
end
function classCombat:GetStartTime()
return self.start_time
end
+82 -98
View File
@@ -377,7 +377,8 @@
--create a new combat object and preplace the current one
local newCombatObject = Details.combate:NovaTabela(true, Details.tabela_overall, combatCounter, ...)
Details.tabela_vigente = newCombatObject
Details:SetCurrentCombat(newCombatObject)
--flag this combat as being created
newCombatObject.IsBeingCreated = true
@@ -514,14 +515,17 @@
Details:Msg("(debug) |cFFFFFF00ended a combat|r|cFFFF7700", Details.encounter_table and Details.encounter_table.name or "")
end
if (Details.tabela_vigente.bIsClosed) then
---@type combat
local currentCombat = Details:GetCurrentCombat()
if (currentCombat.bIsClosed) then
return
end
Details.tabela_vigente.bIsClosed = true
currentCombat.bIsClosed = true
if (Details.tabela_vigente.__destroyed) then
if (currentCombat.__destroyed) then
Details:Msg("a deleted combat was found during combat end, please report this bug on discord:")
Details:Msg("combat destroyed by:", Details.tabela_vigente.__destroyedBy)
Details:Msg("combat destroyed by:", currentCombat.__destroyedBy)
end
--flag the addon as 'leaving combat'
@@ -538,13 +542,12 @@
--Details222.TimeCapture.StopCombat() --it did not start
--check if this isn't a boss and try to find a boss in the segment
if (not Details.tabela_vigente.is_boss) then
if (not currentCombat.is_boss) then
--if this is a mythic+ dungeon, do not scan for encounter journal boss names in the actor list
Details:FindBoss()
--still didn't find the boss
if (not Details.tabela_vigente.is_boss) then
if (not currentCombat.is_boss) then
local ZoneName, _, DifficultyID, _, _, _, _, ZoneMapID = GetInstanceInfo()
local findboss = Details:GetRaidBossFindFunction (ZoneMapID)
if (findboss) then
@@ -558,34 +561,34 @@
Details:OnCombatPhaseChanged() --.PhaseData is nil here on alpha-32
if (Details.tabela_vigente.bossFunction) then
Details:CancelTimer(Details.tabela_vigente.bossFunction)
Details.tabela_vigente.bossFunction = nil
if (currentCombat.bossFunction) then
Details:CancelTimer(currentCombat.bossFunction)
currentCombat.bossFunction = nil
end
--stop combat ticker
Details:StopCombatTicker()
--lock timers
Details.tabela_vigente:LockActivityTime()
currentCombat:LockActivityTime()
--get waste shields
if (Details.close_shields) then
Details:CloseShields (Details.tabela_vigente)
Details:CloseShields (currentCombat)
end
--salva hora, minuto, segundo do fim da luta
Details.tabela_vigente:seta_data (Details._detalhes_props.DATA_TYPE_END)
Details.tabela_vigente:seta_tempo_decorrido()
currentCombat:seta_data (Details._detalhes_props.DATA_TYPE_END)
currentCombat:seta_tempo_decorrido()
--drop last events table to garbage collector
Details.tabela_vigente.player_last_events = {}
currentCombat.player_last_events = {}
--flag instance type
local _, InstanceType = GetInstanceInfo()
Details.tabela_vigente.instance_type = InstanceType
currentCombat.instance_type = InstanceType
if (not Details.tabela_vigente.is_boss and bIsFromEncounterEnd and type(bIsFromEncounterEnd) == "table") then
if (not currentCombat.is_boss and bIsFromEncounterEnd and type(bIsFromEncounterEnd) == "table") then
local encounterID, encounterName, difficultyID, raidSize, endStatus = unpack(bIsFromEncounterEnd)
if (encounterID) then
local ZoneName, InstanceType, DifficultyID, DifficultyName, _, _, _, ZoneMapID = GetInstanceInfo()
@@ -603,7 +606,7 @@
end
local _, boss_index = Details:GetBossEncounterDetailsFromEncounterId (ZoneMapID, encounterID)
Details.tabela_vigente.is_boss = {
currentCombat.is_boss = {
index = boss_index or 0,
name = encounterName,
encounter = encounterName,
@@ -621,83 +624,68 @@
--tag as a mythic dungeon segment, can be any type of segment, this tag also avoid the segment to be tagged as trash
local mythicLevel = C_ChallengeMode and C_ChallengeMode.GetActiveKeystoneInfo()
if (mythicLevel and mythicLevel >= 2) then
Details.tabela_vigente.is_mythic_dungeon_segment = true
Details.tabela_vigente.is_mythic_dungeon_run_id = Details.mythic_dungeon_id
currentCombat.is_mythic_dungeon_segment = true
currentCombat.is_mythic_dungeon_run_id = Details.mythic_dungeon_id
end
--send item level after a combat if is in raid or party group
C_Timer.After(1, Details.ScheduleSyncPlayerActorData)
--if this segment isn't a boss fight
if (not Details.tabela_vigente.is_boss) then
if (Details.tabela_vigente.is_pvp or Details.tabela_vigente.is_arena) then
if (not currentCombat.is_boss) then
if (currentCombat.is_pvp or currentCombat.is_arena) then
Details:FlagActorsOnPvPCombat()
end
if (Details.tabela_vigente.is_arena) then
Details.tabela_vigente.enemy = "[" .. ARENA .. "] " .. Details.tabela_vigente.is_arena.name
if (currentCombat.is_arena) then
currentCombat.enemy = "[" .. ARENA .. "] " .. currentCombat.is_arena.name
end
local in_instance = IsInInstance() --garrison returns party as instance type.
if ((InstanceType == "party" or InstanceType == "raid") and in_instance) then
if (InstanceType == "party") then
if (Details.tabela_vigente.is_mythic_dungeon_segment) then --setted just above
if (currentCombat.is_mythic_dungeon_segment) then --setted just above
--is inside a mythic+ dungeon and this is not a boss segment, so tag it as a dungeon mythic+ trash segment
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
Details.tabela_vigente.is_mythic_dungeon_trash = {
currentCombat.is_mythic_dungeon_trash = {
ZoneName = zoneName,
MapID = instanceMapID,
Level = Details.MythicPlus.Level,
EJID = Details.MythicPlus.ejID,
}
Details:Msg("segment tagged as mythic+ trash.")
else
--tag the combat as trash clean up
Details.tabela_vigente.is_trash = true
currentCombat.is_trash = true
end
else
Details.tabela_vigente.is_trash = true
currentCombat.is_trash = true
end
else
if (not in_instance) then
if (Details.world_combat_is_trash) then
Details.tabela_vigente.is_world_trash_combat = true
currentCombat.is_world_trash_combat = true
end
end
end
if (not Details.tabela_vigente.enemy) then
if (not currentCombat.enemy) then
local enemy = Details:FindEnemy()
if (enemy and Details.debug) then
Details:Msg("(debug) enemy found", enemy)
end
Details.tabela_vigente.enemy = enemy
end
if (Details.debug) then
-- Details:Msg("(debug) forcing equalize actors behavior.")
-- Details:EqualizeActorsSchedule (Details.host_of)
currentCombat.enemy = enemy
end
Details:FlagActorsOnCommonFight() --fight_component
else
--this segment is a boss fight
if (not InCombatLockdown() and not UnitAffectingCombat("player")) then
else
--Details.schedule_flag_boss_components = true
end
--calling here without checking for combat since the does not ran too long for scripts
Details:FlagActorsOnBossFight()
local boss_id = Details.encounter_table.id
if (bossKilled) then
Details.tabela_vigente.is_boss.killed = true
currentCombat.is_boss.killed = true
--add to storage
if (not InCombatLockdown() and not UnitAffectingCombat("player") and not Details.logoff_saving_data) then
@@ -709,11 +697,11 @@
Details.schedule_store_boss_encounter = true
end
Details:SendEvent("COMBAT_BOSS_DEFEATED", nil, Details.tabela_vigente)
Details:SendEvent("COMBAT_BOSS_DEFEATED", nil, currentCombat)
Details:CheckFor_TrashSuppressionOnEncounterEnd()
else
Details:SendEvent("COMBAT_BOSS_WIPE", nil, Details.tabela_vigente)
Details:SendEvent("COMBAT_BOSS_WIPE", nil, currentCombat)
--add to storage
if (not InCombatLockdown() and not UnitAffectingCombat("player") and not Details.logoff_saving_data) then
@@ -724,17 +712,15 @@
else
Details.schedule_store_boss_encounter_wipe = true
end
end
Details.tabela_vigente.is_boss.index = Details.tabela_vigente.is_boss.index or 1
currentCombat.is_boss.index = currentCombat.is_boss.index or 1
Details.tabela_vigente.enemy = Details.tabela_vigente.is_boss.encounter
if (Details.tabela_vigente.instance_type == "raid") then
currentCombat.enemy = currentCombat.is_boss.encounter
if (currentCombat.instance_type == "raid") then
Details.last_encounter2 = Details.last_encounter
Details.last_encounter = Details.tabela_vigente.is_boss.name
Details.last_encounter = currentCombat.is_boss.name
if (Details.pre_pot_used) then
Details.last_combat_pre_pot_used = Details.CopyTable(Details.pre_pot_used)
@@ -748,17 +734,17 @@
if (bIsFromEncounterEnd) then
if (Details.encounter_table.start) then
Details.tabela_vigente:SetStartTime (Details.encounter_table.start)
currentCombat:SetStartTime(Details.encounter_table.start)
end
Details.tabela_vigente:SetEndTime (Details.encounter_table ["end"] or GetTime())
currentCombat:SetEndTime(Details.encounter_table["end"] or GetTime())
end
--encounter boss function
local bossFunction, bossFunctionType = Details:GetBossFunction (Details.tabela_vigente.is_boss.mapid or 0, Details.tabela_vigente.is_boss.index or 0)
local bossFunction, bossFunctionType = Details:GetBossFunction(currentCombat.is_boss.mapid or 0, currentCombat.is_boss.index or 0)
if (bossFunction) then
if (bitBand(bossFunctionType, 0x2) ~= 0) then --end of combat
if (not Details.logoff_saving_data) then
local successful, errortext = pcall(bossFunction, Details.tabela_vigente)
local successful, errortext = pcall(bossFunction, currentCombat)
if (not successful) then
Details:Msg("error occurred on Encounter Boss Function:", errortext)
end
@@ -766,14 +752,12 @@
end
end
if (Details.tabela_vigente.instance_type == "raid") then
--schedule captures off
Details:CaptureSet (false, "damage", false, 15)
Details:CaptureSet (false, "energy", false, 15)
Details:CaptureSet (false, "aura", false, 15)
Details:CaptureSet (false, "energy", false, 15)
Details:CaptureSet (false, "spellcast", false, 15)
if (currentCombat.instance_type == "raid") then
Details:CaptureSet(false, "damage", false, 15)
Details:CaptureSet(false, "energy", false, 15)
Details:CaptureSet(false, "aura", false, 15)
Details:CaptureSet(false, "energy", false, 15)
Details:CaptureSet(false, "spellcast", false, 15)
if (Details.debug) then
Details:Msg("(debug) freezing parser for 15 seconds.")
@@ -781,8 +765,8 @@
end
--schedule sync
Details:EqualizeActorsSchedule (Details.host_of)
if (Details:GetEncounterEqualize (Details.tabela_vigente.is_boss.mapid, Details.tabela_vigente.is_boss.index)) then
Details:EqualizeActorsSchedule(Details.host_of)
if (Details:GetEncounterEqualize(currentCombat.is_boss.mapid, currentCombat.is_boss.index)) then
Details:ScheduleTimer("DelayedSyncAlert", 3)
end
end
@@ -792,7 +776,7 @@
Details.CloseSoloDebuffs()
end
local tempo_do_combate = Details.tabela_vigente:GetCombatTime()
local tempo_do_combate = currentCombat:GetCombatTime()
---@type combat
local invalidCombat
@@ -805,11 +789,11 @@
local zoneName, zoneType = GetInstanceInfo()
if (not bShouldForceDiscard and (zoneType == "none" or tempo_do_combate >= Details.minimum_combat_time or not segmentsTable[1])) then
--combat accepted
Details.tabela_historico:AddCombat(Details.tabela_vigente) --move a tabela atual para dentro do histrico
if (Details.tabela_vigente.is_boss) then
Details.tabela_historico:AddCombat(currentCombat) --move a tabela atual para dentro do histrico
if (currentCombat.is_boss) then
if (IsInRaid()) then
local cleuID = Details.tabela_vigente.is_boss.id
local diff = Details.tabela_vigente.is_boss.diff
local cleuID = currentCombat.is_boss.id
local diff = currentCombat.is_boss.diff
if (cleuID and diff == 16) then -- 16 mythic
local raidData = Details.raid_data
@@ -821,60 +805,60 @@
end
--get or build a table for this cleuID
mythicRaidData [cleuID] = mythicRaidData [cleuID] or {wipes = 0, kills = 0, best_try = 1, longest = 0, try_history = {}}
local cleuIDData = mythicRaidData [cleuID]
mythicRaidData[cleuID] = mythicRaidData[cleuID] or {wipes = 0, kills = 0, best_try = 1, longest = 0, try_history = {}}
local cleuIDData = mythicRaidData[cleuID]
--store encounter data for plugins and weakauras
if (Details.tabela_vigente:GetCombatTime() > cleuIDData.longest) then
cleuIDData.longest = Details.tabela_vigente:GetCombatTime()
if (currentCombat:GetCombatTime() > cleuIDData.longest) then
cleuIDData.longest = currentCombat:GetCombatTime()
end
if (Details.tabela_vigente.is_boss.killed) then
if (currentCombat.is_boss.killed) then
cleuIDData.kills = cleuIDData.kills + 1
cleuIDData.best_try = 0
table.insert(cleuIDData.try_history, {0, Details.tabela_vigente:GetCombatTime()})
table.insert(cleuIDData.try_history, {0, currentCombat:GetCombatTime()})
--print("KILL", "best try", cleuIDData.best_try, "amt kills", cleuIDData.kills, "wipes", cleuIDData.wipes, "longest", cleuIDData.longest)
else
cleuIDData.wipes = cleuIDData.wipes + 1
if (Details.boss1_health_percent and Details.boss1_health_percent < cleuIDData.best_try) then
cleuIDData.best_try = Details.boss1_health_percent
table.insert(cleuIDData.try_history, {Details.boss1_health_percent, Details.tabela_vigente:GetCombatTime()})
table.insert(cleuIDData.try_history, {Details.boss1_health_percent, currentCombat:GetCombatTime()})
end
--print("WIPE", "best try", cleuIDData.best_try, "amt kills", cleuIDData.kills, "wipes", cleuIDData.wipes, "longest", cleuIDData.longest)
end
end
end
--
end
--the combat is valid, see if the user is sharing data with somebody
if (Details.shareData) then
local zipData = Details:CompressData (Details.tabela_vigente, "comm")
local zipData = Details:CompressData(currentCombat, "comm")
if (zipData) then
print("has zip data")
end
end
else
--combat denied: combat did not pass the filter and cannot be added into the segment history
--rewind the data set to the first slot in the segments table
showTutorialForDiscardedSegment()
--change the current combat to the latest combat available in the segment table
invalidCombat = Details.tabela_vigente
Details.tabela_vigente = segmentsTable[1]
invalidCombat = currentCombat
Details:SetCurrentCombat(segmentsTable[1])
currentCombat = Details:GetCurrentCombat()
--if it rewinds to an already erased combat, then create a new combat
if (Details.tabela_vigente.__destroyed) then
Details.tabela_vigente = Details.combate:NovaTabela(nil, Details.tabela_overall)
if (currentCombat.__destroyed) then
Details:SetCurrentCombat(Details.combate:NovaTabela(nil, Details.tabela_overall))
currentCombat = Details:GetCurrentCombat()
end
if (Details.tabela_vigente:GetStartTime() == 0) then
Details.tabela_vigente:SetStartTime(GetTime())
Details.tabela_vigente:SetEndTime(GetTime())
if (currentCombat:GetStartTime() == 0) then
currentCombat:SetStartTime(GetTime())
currentCombat:SetEndTime(GetTime())
end
Details.tabela_vigente.resincked = true
currentCombat.resincked = true
Details:InstanceCallDetailsFunc(Details.AtualizarJanela)
if (Details.solo) then --code to update "solo" plugins, there's no solo plugins for details! at the moment
@@ -905,8 +889,8 @@
Details.in_combat = false
Details.leaving_combat = false
Details:Destroy(Details.tabela_vigente.PhaseData.damage_section)
Details:Destroy(Details.tabela_vigente.PhaseData.heal_section)
Details:Destroy(currentCombat.PhaseData.damage_section)
Details:Destroy(currentCombat.PhaseData.heal_section)
Details:Destroy(Details.cache_damage_group)
Details:Destroy(Details.cache_healing_group)
@@ -938,7 +922,7 @@
Details:SendEvent("COMBAT_INVALID")
Details:SendEvent("COMBAT_PLAYER_LEAVE", nil, invalidCombat)
else
Details:SendEvent("COMBAT_PLAYER_LEAVE", nil, Details.tabela_vigente)
Details:SendEvent("COMBAT_PLAYER_LEAVE", nil, currentCombat)
end
Details:CheckForTextTimeCounter()
@@ -948,7 +932,7 @@
--issue: invalidCombat will be just floating around in memory if not destroyed
end --end of leaving combat function
function Details:GetPlayersInArena()
function Details:GetPlayersInArena() --ARENA_OPPONENT_UPDATE
local aliados = GetNumGroupMembers() -- LE_PARTY_CATEGORY_HOME
for i = 1, aliados-1 do
local role = UnitGroupRolesAssigned and UnitGroupRolesAssigned("party" .. i) or "DAMAGER"
+17
View File
@@ -603,6 +603,23 @@ local classTypeUtility = Details.atributos.misc
actorContainer:Cleanup()
end
end
else
if (combatObject.is_mythic_dungeon_segment) then
for i = 1, DETAILS_COMBAT_AMOUNT_CONTAINERS do
---@type actorcontainer
local actorContainer = combatObject:GetContainer(i)
if (actorContainer) then
local actorTable = actorContainer:GetActorTable()
for o = #actorTable, 1, -1 do
---@type actor
local actorObject = actorTable[o]
for funcName in pairs(Details222.Mixins.ActorMixin) do
actorObject[funcName] = nil
end
end
end
end
end
end
end
+54 -15
View File
@@ -57,22 +57,22 @@
local _spell_energy_func = Details.habilidade_e_energy.Add
local _spell_utility_func = Details.habilidade_misc.Add
--current combat and overall pointers
local _current_combat = Details.tabela_vigente or {} --placeholder table
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--cache
--cache current combat
local _current_combat = Details.tabela_vigente or {} --placeholder table
--total container pointers
local _current_total = _current_combat.totals
local _current_gtotal = _current_combat.totals_grupo
--cache total table
local _current_total = _current_combat.totals
local _current_gtotal = _current_combat.totals_grupo
--actors container pointers
local _current_damage_container = _current_combat [1]
local _current_heal_container = _current_combat [2]
local _current_energy_container = _current_combat [3]
local _current_misc_container = _current_combat [4]
--cache actors containers
local _current_damage_container = _current_combat [1]
local _current_heal_container = _current_combat [2]
local _current_energy_container = _current_combat [3]
local _current_misc_container = _current_combat [4]
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--cache
local names_cache = {}
local names_cache = {}
--damage
local damage_cache = setmetatable({}, Details.weaktable)
local damage_cache_pets = setmetatable({}, Details.weaktable)
@@ -467,6 +467,9 @@
--Volatile Spark on razga'reth
[194999] = true,
--Ozumat - Throne of Tides
[44566] = true,
}
local ignored_npcids = {}
@@ -5758,19 +5761,53 @@ local SPELL_POWER_PAIN = SPELL_POWER_PAIN or (PowerEnum and PowerEnum.Pain) or 1
end
end
function Details.parser_functions:CHALLENGE_MODE_END(...) --doesn't exists
Details:Msg("CHALLENGE_MODE_END", GetTime())
end
--WORLD_STATE_TIMER_START are a timer only used on scenarios
function Details.parser_functions:WORLD_STATE_TIMER_START(...)
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
if (difficultyID == 8) then
if (Details222.MythicPlus.CHALLENGE_MODE_START_AT + 10 > GetTime()) then
if (not Details222.MythicPlus.WorldStateTimerStartAt) then
local payload1, payload2, payload3 = ...
payload1 = payload1 or ""
payload2 = payload2 or ""
payload3 = payload3 or ""
Details222.MythicPlus.LogStep("Event: WORLD_STATE_TIMER_START | payload1: " .. payload1 .. " | payload2: " .. payload2 .. " | payload3: " .. payload3)
Details:SendEvent("COMBAT_MYTHICDUNGEON_START")
Details222.MythicPlus.WorldStateTimerStartAt = time()
end
end
end
end
function Details.parser_functions:CHALLENGE_MODE_START(...)
--send mythic dungeon start event
if (Details.debug) then
print("parser event", "CHALLENGE_MODE_START", ...)
end
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
if (difficultyID == 8) then
Details:SendEvent("COMBAT_MYTHICDUNGEON_START")
Details222.MythicPlus.CHALLENGE_MODE_START_AT = GetTime()
Details222.MythicPlus.WorldStateTimerStartAt = nil
Details222.MythicPlus.WorldStateTimerEndAt = nil
Details222.MythicPlus.LogStep("Event: CHALLENGE_MODE_START")
end
end
function Details.parser_functions:CHALLENGE_MODE_COMPLETED(...)
Details222.MythicPlus.WorldStateTimerEndAt = time()
local mapChallengeModeID, level, time, onTime, keystoneUpgradeLevels, practiceRun,
oldOverallDungeonScore, newOverallDungeonScore, IsMapRecord, IsAffixRecord,
PrimaryAffix, isEligibleForScore, members
= C_ChallengeMode.GetCompletionInfo()
Details222.MythicPlus.time = math.floor(time / 1000)
Details222.MythicPlus.bOnTime = onTime
--send mythic dungeon end event
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
if (difficultyID == 8) then
@@ -5806,6 +5843,8 @@ local SPELL_POWER_PAIN = SPELL_POWER_PAIN or (PowerEnum and PowerEnum.Pain) or 1
if (not okay) then
Details:Msg("something went wrong (0x7878):", errorText)
end
Details222.MythicPlus.LogStep("===== Mythic+ Finished =====")
end
function Details.parser_functions:PLAYER_REGEN_ENABLED(...)
+2 -2
View File
@@ -9006,11 +9006,11 @@ end
gameCooltip:AddLine("Remove Common Segments", nil, 1, "white", nil, Details.font_sizes.menus, Details.font_faces.menus)
gameCooltip:AddIcon([[Interface\Buttons\UI-StopButton]], 1, 1, 14, 14, 0, 1, 0, 1, "orange")
gameCooltip:AddMenu(1, function() return Details.tabela_historico:ResetDataByCombatType("generic") end)
gameCooltip:AddMenu(1, function() Details.tabela_historico:ResetDataByCombatType("generic"); GameCooltip:Hide() end)
gameCooltip:AddLine("Reset, but keep Mythic+ Overall Segments", nil, 1, "white", nil, Details.font_sizes.menus, Details.font_faces.menus)
gameCooltip:AddIcon([[Interface\Buttons\UI-StopButton]], 1, 1, 14, 14, 0, 1, 0, 1, "orange")
gameCooltip:AddMenu(1, function() return Details.tabela_historico:ResetDataByCombatType("m+overall") end)
gameCooltip:AddMenu(1, function() Details.tabela_historico:ResetDataByCombatType("m+overall"); GameCooltip:Hide() end)
gameCooltip:AddLine("$div", nil, 1, nil, -5, -11)
+2 -11
View File
@@ -6401,7 +6401,8 @@ do
return Details:Msg(Loc ["STRING_OPTIONS_SPELL_IDERROR"])
end
Details:UserCustomSpellAdd (id, name, icon)
local bAddedByUser = true
Details:UserCustomSpellAdd (id, name, icon, bAddedByUser)
panel:Refresh()
@@ -6910,16 +6911,6 @@ do
desc = "When the run is done, make an overall segment.",
},
{--overall only with bosses
type = "toggle",
get = function() return Details.mythic_plus.make_overall_boss_only end,
set = function(self, fixedparam, value)
Details.mythic_plus.make_overall_boss_only = value
end,
name = "Overall Segment Boss Only",
desc = "Only add boss segments on the overall.",
},
{--merge trash
type = "toggle",
get = function() return Details.mythic_plus.merge_boss_trash end,
+60 -46
View File
@@ -49,10 +49,8 @@ end
--]]
--precisa converter um wipe em um trash segment? provavel que sim
-- at the end of a mythic run, if enable on settings, merge all the segments from the mythic run into only one
function DetailsMythicPlusFrame.MergeSegmentsOnEnd() --~merge
--at the end of a mythic run, if enable on settings, merge all the segments from the mythic run into only one
if (DetailsMythicPlusFrame.DevelopmentDebug) then
print("Details!", "MergeSegmentsOnEnd() > starting to merge mythic segments.", "InCombatLockdown():", InCombatLockdown())
end
@@ -66,16 +64,18 @@ function DetailsMythicPlusFrame.MergeSegmentsOnEnd() --~merge
local newCombat = Details:GetCurrentCombat()
local segmentsTable = Details:GetCombatSegments()
local totalTime = 0
local timeInCombat = 0
local startDate, endDate = "", ""
local lastSegment
local totalSegments = 0
--copy deaths occured on all segments to the new segment, also sum the activity combat time
if (Details.mythic_plus.reverse_death_log) then
for i = 1, 40 do --copy the deaths from the first segment to the last one
local thisCombat = segmentsTable[i]
if (thisCombat and thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
newCombat:CopyDeathsFrom(thisCombat, true)
timeInCombat = timeInCombat + thisCombat:GetCombatTime()
end
end
else
@@ -84,11 +84,30 @@ function DetailsMythicPlusFrame.MergeSegmentsOnEnd() --~merge
if (thisCombat) then
if (thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
newCombat:CopyDeathsFrom(thisCombat, true)
timeInCombat = timeInCombat + thisCombat:GetCombatTime()
end
end
end
end
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
--tag the segment as mythic overall segment
newCombat.is_mythic_dungeon = {
StartedAt = Details.MythicPlus.StartedAt, --the start of the run
EndedAt = Details.MythicPlus.EndedAt, --the end of the run
WorldStateTimerStart = Details222.MythicPlus.WorldStateTimerStartAt,
WorldStateTimerEnd = Details222.MythicPlus.WorldStateTimerEndAt,
TimeInCombat = timeInCombat,
SegmentID = "overall", --segment number within the dungeon
RunID = Details.mythic_dungeon_id,
OverallSegment = true,
ZoneName = Details.MythicPlus.DungeonName,
MapID = instanceMapID,
Level = Details.MythicPlus.Level,
EJID = Details.MythicPlus.ejID,
}
--add all boss segments from this run to this new segment
for i = 1, 40 do --from the newer combat to the oldest
local thisCombat = segmentsTable[i]
@@ -96,15 +115,12 @@ function DetailsMythicPlusFrame.MergeSegmentsOnEnd() --~merge
local canAddThisSegment = true
if (Details.mythic_plus.make_overall_boss_only) then
if (not thisCombat.is_boss) then
canAddThisSegment = false
--canAddThisSegment = false --disabled
end
end
if (canAddThisSegment) then
newCombat = newCombat + thisCombat
--newCombat:CopyDeathsFrom(thisCombat, true)
totalTime = totalTime + thisCombat:GetCombatTime()
totalSegments = totalSegments + 1
if (DetailsMythicPlusFrame.DevelopmentDebug) then
@@ -113,7 +129,7 @@ function DetailsMythicPlusFrame.MergeSegmentsOnEnd() --~merge
if (endDate == "") then
local _, whenEnded = thisCombat:GetDate()
endDate =whenEnded
endDate = whenEnded
end
lastSegment = thisCombat
end
@@ -126,33 +142,33 @@ function DetailsMythicPlusFrame.MergeSegmentsOnEnd() --~merge
end
if (DetailsMythicPlusFrame.DevelopmentDebug) then
print("Details!", "MergeSegmentsOnEnd() > totalTime:", totalTime, "startDate:", startDate)
print("Details!", "MergeSegmentsOnEnd() > totalTime:", timeInCombat, "startDate:", startDate)
end
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
--tag the segment as mythic overall segment
newCombat.is_mythic_dungeon = {
StartedAt = Details.MythicPlus.StartedAt, --the start of the run
EndedAt = Details.MythicPlus.EndedAt, --the end of the run
SegmentID = "overall", --segment number within the dungeon
RunID = Details.mythic_dungeon_id,
OverallSegment = true,
ZoneName = Details.MythicPlus.DungeonName,
MapID = instanceMapID,
Level = Details.MythicPlus.Level,
EJID = Details.MythicPlus.ejID,
}
newCombat.total_segments_added = totalSegments
newCombat.is_mythic_dungeon_segment = true
newCombat.is_mythic_dungeon_run_id = Details.mythic_dungeon_id
--check if both values are valid, this can get invalid if the player leaves the dungeon before the timer ends or the game crashes
if (type(Details222.MythicPlus.time) == "number") then
newCombat.run_time = Details222.MythicPlus.time
Details222.MythicPlus.LogStep("GetCompletionInfo() Found, Time: " .. Details222.MythicPlus.time)
elseif (newCombat.is_mythic_dungeon.WorldStateTimerEnd and newCombat.is_mythic_dungeon.WorldStateTimerStart) then
local runTime = newCombat.is_mythic_dungeon.WorldStateTimerEnd - newCombat.is_mythic_dungeon.WorldStateTimerStart
newCombat.run_time = Details222.MythicPlus.time
Details222.MythicPlus.LogStep("World State Timers is Available, Run Time: " .. runTime .. "| start:" .. newCombat.is_mythic_dungeon.WorldStateTimerStart .. "| end:" .. newCombat.is_mythic_dungeon.WorldStateTimerEnd)
else
newCombat.run_time = timeInCombat
Details222.MythicPlus.LogStep("GetCompletionInfo() and World State Timers not Found, Activity Time: " .. timeInCombat)
end
newCombat:SetStartTime(GetTime() - timeInCombat)
newCombat:SetEndTime(GetTime())
Details222.MythicPlus.LogStep("Activity Time: " .. timeInCombat)
--set the segment time and date
newCombat:SetStartTime (GetTime() - totalTime)
newCombat:SetEndTime (GetTime())
newCombat:SetDate (startDate, endDate)
newCombat:SetDate(startDate, endDate)
--immediatly finishes the segment just started
Details:SairDoCombate()
@@ -391,9 +407,9 @@ function DetailsMythicPlusFrame.MergeRemainingTrashAfterAllBossesDone()
end
end
--this function is called right after defeat a boss inside a mythic dungeon
--it comes from details! control leave combat
function DetailsMythicPlusFrame.BossDefeated(this_is_end_end, encounterID, encounterName, difficultyID, raidSize, endStatus) --hold your breath and count to ten
--this function is called right after defeat a boss inside a mythic dungeon
--it comes from details! control leave combat
if (DetailsMythicPlusFrame.DevelopmentDebug) then
print("Details!", "BossDefeated() > boss defeated | SegmentID:", Details.MythicPlus.SegmentID, " | mapID:", Details.MythicPlus.DungeonID)
end
@@ -650,13 +666,13 @@ function DetailsMythicPlusFrame.MythicDungeonStarted()
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
local zoneName, _, _, _, _, _, _, currentZoneID = GetInstanceInfo()
local mapID = C_Map.GetBestMapForUnit ("player")
local mapID = C_Map.GetBestMapForUnit("player")
if (not mapID) then
return
end
local ejID = DF.EncounterJournal.EJ_GetInstanceForMap (mapID)
local ejID = DF.EncounterJournal.EJ_GetInstanceForMap(mapID)
--setup the mythic run info
Details.MythicPlus.Started = true
@@ -669,12 +685,12 @@ function DetailsMythicPlusFrame.MythicDungeonStarted()
Details.MythicPlus.ejID = ejID
Details.MythicPlus.PreviousBossKilledAt = time()
Details:SaveState_CurrentMythicDungeonRun (Details.mythic_dungeon_id, zoneName, currentZoneID, time()+9.7, 1, mythicLevel, ejID, time())
Details:SaveState_CurrentMythicDungeonRun(Details.mythic_dungeon_id, zoneName, currentZoneID, time()+9.7, 1, mythicLevel, ejID, time())
local name, groupType, difficultyID, difficult = GetInstanceInfo()
if (groupType == "party" and Details.overall_clear_newchallenge) then
Details.historico:ResetOverallData()
Details:Msg("overall data are now reset.")
Details:Msg("the overall data has been reset.") --localize-me
if (Details.debug) then
Details:Msg("(debug) timer is for a mythic+ dungeon, overall has been reseted.")
@@ -684,19 +700,17 @@ function DetailsMythicPlusFrame.MythicDungeonStarted()
if (DetailsMythicPlusFrame.DevelopmentDebug) then
print("Details!", "MythicDungeonStarted() > State set to Mythic Dungeon, new combat starting in 10 seconds.")
end
end
function DetailsMythicPlusFrame.OnChallengeModeStart()
--is this a mythic dungeon?
local _, _, difficulty, _, _, _, _, currentZoneID = GetInstanceInfo()
local _, _, difficultyID, _, _, _, _, currentZoneID = GetInstanceInfo()
if (difficulty == 8 and DetailsMythicPlusFrame.LastTimer and DetailsMythicPlusFrame.LastTimer+2 > GetTime()) then
if (difficultyID == 8) then
--start the dungeon on Details!
DetailsMythicPlusFrame.MythicDungeonStarted()
--print("D! mythic dungeon started!")
Details222.MythicPlus.LogStep("OnChallengeModeStart()")
else
--print("D! mythic dungeon was already started!")
--from zone changed
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
@@ -794,10 +808,10 @@ function DetailsMythicPlusFrame.EventListener.OnDetailsEvent(contextObject, even
lowerInstance = Details:GetInstance(lowerInstance)
if (lowerInstance) then
C_Timer.After(3, function()
if (lowerInstance:IsEnabled()) then
--if (lowerInstance:IsEnabled()) then
--todo, need localization
lowerInstance:InstanceAlert("Details!" .. " " .. "Damage" .. " " .. "Meter", {[[Interface\AddOns\Details\images\minimap]], 16, 16, false}, 3, {function() end}, false, true)
end
--lowerInstance:InstanceAlert("Details!" .. " " .. "Damage" .. " " .. "Meter", {[[Interface\AddOns\Details\images\minimap]], 16, 16, false}, 3, {function() end}, false, true)
--end
end)
end
end
@@ -812,7 +826,7 @@ function DetailsMythicPlusFrame.EventListener.OnDetailsEvent(contextObject, even
Details:Destroy(Details.cached_specs)
end
C_Timer.After(0.5, DetailsMythicPlusFrame.OnChallengeModeStart)
C_Timer.After(0.25, DetailsMythicPlusFrame.OnChallengeModeStart)
--debugging
local mPlusSettings = Details.mythic_plus
@@ -825,7 +839,7 @@ function DetailsMythicPlusFrame.EventListener.OnDetailsEvent(contextObject, even
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
local zoneName, _, _, _, _, _, _, currentZoneID = GetInstanceInfo()
Details222.MythicPlus.LogStep("CHALLENGE_MODE_START | settings: " .. result .. " | level: " .. mythicLevel .. " | zone: " .. zoneName .. " | zoneId: " .. currentZoneID)
Details222.MythicPlus.LogStep("COMBAT_MYTHICDUNGEON_START | settings: " .. result .. " | level: " .. mythicLevel .. " | zone: " .. zoneName .. " | zoneId: " .. currentZoneID)
elseif (event == "COMBAT_MYTHICDUNGEON_END") then
--ignore the event if ignoring mythic dungeon special treatment
@@ -842,7 +856,7 @@ end
DetailsMythicPlusFrame:SetScript("OnEvent", function(_, event, ...)
if (event == "START_TIMER") then
DetailsMythicPlusFrame.LastTimer = GetTime()
--DetailsMythicPlusFrame.LastTimer = GetTime()
elseif (event == "ZONE_CHANGED_NEW_AREA") then
if (DetailsMythicPlusFrame.IsDoingMythicDungeon) then
+11 -1
View File
@@ -495,6 +495,13 @@ function Details:ApplyProfile(profileName, bNoSave, bIsCopy)
Details.time_type = 2
end
Details.capture_real["damage"] = true
Details.capture_real["heal"] = true
Details.capture_real["energy"] = true
Details.capture_real["miscdata"] = true
Details.capture_real["aura"] = true
Details.capture_real["spellcast"] = true
return true
end
@@ -1346,6 +1353,7 @@ local default_global_data = {
custom = {},
savedStyles = {},
savedCustomSpells = {},
userCustomSpells = {}, --spells modified by the user
savedTimeCaptures = {},
lastUpdateWarning = 0,
update_warning_timeout = 10,
@@ -1594,7 +1602,9 @@ local default_global_data = {
mythicrun_chart_frame = {},
mythicrun_chart_frame_minimized = {},
mythicrun_chart_frame_ready = {},
},
mythicrun_time_type = 1, --1: combat time (the amount of time the player is in combat) 2: run time (the amount of time it took to finish the mythic+ run)
}, --implementar esse time_type quando estiver dando refresh na janela
--plugin window positions
plugin_window_pos = {},
+17 -4
View File
@@ -336,12 +336,15 @@ do
return customItemList
end
function Details:UserCustomSpellUpdate(index, spellName, spellIcon)
function Details:UserCustomSpellUpdate(index, spellName, spellIcon) --called from the options panel > rename spells
---@type savedspelldata
local savedSpellData = Details.savedCustomSpells[index]
if (savedSpellData) then
local spellId = savedSpellData[1]
savedSpellData[2], savedSpellData[3] = spellName or savedSpellData[2], spellIcon or savedSpellData[3]
return rawset(Details.spellcache, savedSpellData[1], {savedSpellData[2], 1, savedSpellData[3]})
rawset(Details.spellcache, spellId, {savedSpellData[2], 1, savedSpellData[3]})
Details.userCustomSpells[spellId] = true
return true
else
return false
end
@@ -416,7 +419,13 @@ do
end
end
function Details:UserCustomSpellAdd(spellId, spellName, spellIcon)
function Details:UserCustomSpellAdd(spellId, spellName, spellIcon, bAddedByUser)
if (Details.userCustomSpells[spellId]) then
if (not bAddedByUser) then
return
end
end
local isOverwrite = false
for index, savedSpellData in ipairs(Details.savedCustomSpells) do
if (savedSpellData[1] == spellId) then
@@ -431,7 +440,11 @@ do
tinsert(Details.savedCustomSpells, {spellId, spellName, spellIcon})
end
return rawset(Details.spellcache, spellId, {spellName, 1, spellIcon})
rawset(Details.spellcache, spellId, {spellName, 1, spellIcon})
if (bAddedByUser) then
Details.userCustomSpells[spellId] = true
end
end
function Details:UserCustomSpellRemove(index)
+3
View File
@@ -276,7 +276,10 @@ function Details:StartMeUp()
Details.listener:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
Details.listener:RegisterEvent("PLAYER_TALENT_UPDATE")
Details.listener:RegisterEvent("CHALLENGE_MODE_START")
--Details.listener:RegisterEvent("CHALLENGE_MODE_END") --doesn't exists ingame (only at cleu)
Details.listener:RegisterEvent("CHALLENGE_MODE_COMPLETED")
Details.listener:RegisterEvent("WORLD_STATE_TIMER_START")
end
Details.parser_frame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")