From 690a0825500193934c303560574824fffd856064 Mon Sep 17 00:00:00 2001 From: Tercio Jose Date: Fri, 18 Oct 2024 13:36:10 -0300 Subject: [PATCH] Framework update --- Libs/DF/addon.lua | 17 +- Libs/DF/auras.lua | 76 +- Libs/DF/button.lua | 63 +- Libs/DF/definitions.lua | 31 +- Libs/DF/dropdown.lua | 133 ++- Libs/DF/ejournal.lua | 360 +++++++ Libs/DF/elapsedtime.lua | 152 +++ Libs/DF/fw.lua | 202 +++- Libs/DF/line_indicator.lua | 467 +++++++++ Libs/DF/load.xml | 3 + Libs/DF/panel.lua | 213 +++++ Libs/DF/picture.lua | 4 +- Libs/DF/savedvars.lua | 2 +- Libs/DF/slider.lua | 17 +- Libs/DF/textentry.lua | 26 + Libs/DF/timebar.lua | 15 +- Libs/DF/timeline.lua | 895 ++++-------------- Libs/LibOpenRaid/GetPlayerInformation.lua | 7 +- Libs/LibOpenRaid/LibOpenRaid.lua | 18 +- .../LibOpenRaid/ThingsToMantain_WarWithin.lua | 37 +- core/parser.lua | 8 +- luaserver.lua | 7 +- 22 files changed, 1980 insertions(+), 773 deletions(-) create mode 100644 Libs/DF/ejournal.lua create mode 100644 Libs/DF/elapsedtime.lua create mode 100644 Libs/DF/line_indicator.lua diff --git a/Libs/DF/addon.lua b/Libs/DF/addon.lua index d41e7ec2c..6cf68e7a3 100644 --- a/Libs/DF/addon.lua +++ b/Libs/DF/addon.lua @@ -49,7 +49,7 @@ local addonLoaded = function(addonFrame, event, addonName) addonObject.profile = profileTable if (addonObject.OnLoad) then - detailsFramework:Dispatch(addonObject.OnLoad, addonObject, addonObject.profile) + detailsFramework:Dispatch(addonObject.OnLoad, addonObject, addonObject.profile, true) end end @@ -65,7 +65,13 @@ end --when the player logout or reloadUI local addonUnload = function(addonFrame) local addonObject = addonFrame.__addonObject - detailsFramework.SavedVars.SaveProfile(addonObject) + local bOkay, errortext = pcall(detailsFramework.SavedVars.SaveProfile, addonObject) + if (not bOkay) then + if (addonFrame.logoutLogs) then + table.insert(addonFrame.logoutLogs, 1, date("%a %b %d %H:%M:%S %Y") .. "|LOGOUT error:" .. errortext) + table.remove(addonFrame.logoutLogs, 3) + end + end end local addonEvents = { @@ -90,6 +96,11 @@ detailsFramework.AddonMixin = { } +--log erros during the save data +local setLogoutLogTable = function(addonObject, logTable) + addonObject.__frame.logoutLogs = logTable +end + ---create an addon object ---@param addonName addonname ---@param globalSavedVariablesName string @@ -115,6 +126,8 @@ function detailsFramework:CreateNewAddOn(addonName, globalSavedVariablesName, sa addonFrame:RegisterEvent("PLAYER_LOGOUT") addonFrame:SetScript("OnEvent", addonOnEvent) + newAddonObject.SetLogoutLogTable = setLogoutLogTable + return newAddonObject end diff --git a/Libs/DF/auras.lua b/Libs/DF/auras.lua index 0745833f9..1d5bce9c7 100644 --- a/Libs/DF/auras.lua +++ b/Libs/DF/auras.lua @@ -584,18 +584,35 @@ function DF:CreateAuraConfigPanel(parent, name, db, changeCallback, options, tex debuffNameTracklistEntry:ClearFocus() if (text ~= "") then - if (not tonumber(text)) then - DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID.") - end + if (text:find(";")) then + for _, spellName in ipairs({strsplit(";", text)}) do + spellName = strtrim(spellName) + if (not tonumber(spellName)) then + DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID: " .. (spellName or "")) + end + + local spellId = getSpellIDFromSpellName(spellName) - --get the spellId - local spellId = getSpellIDFromSpellName(text) - if (not spellId) then - DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") - return - end + if (spellId) then + newAuraPanel.db.aura_tracker.debuff_tracked [spellId] = false + else + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found: " .. (spellName or "")) + end + end + else + if (not tonumber(text)) then + DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID.") + end - newAuraPanel.db.aura_tracker.debuff_tracked [spellId] = false + --get the spellId + local spellId = getSpellIDFromSpellName(text) + if (not spellId) then + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") + return + end + + newAuraPanel.db.aura_tracker.debuff_tracked [spellId] = false + end --refresh the buff blacklist frame newAuraPanel.debuff_tracked:Refresh() @@ -635,19 +652,36 @@ function DF:CreateAuraConfigPanel(parent, name, db, changeCallback, options, tex buffNameTracklistEntry:ClearFocus() if (text ~= "") then - if (not tonumber(text)) then - DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID.") - end + if (text:find(";")) then + for _, spellName in ipairs({strsplit(";", text)}) do + spellName = strtrim(spellName) + if (not tonumber(spellName)) then + DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID: " .. (spellName or "")) + end + + local spellId = getSpellIDFromSpellName(spellName) - --get the spellId - local spellId = getSpellIDFromSpellName(text) - if (not spellId) then - DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") - return - end + if (spellId) then + newAuraPanel.db.aura_tracker.buff_tracked [spellId] = false + else + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found: " .. (spellName or "")) + end + end + else + if (not tonumber(text)) then + DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID.") + end - --add the spellId to the tracklist - newAuraPanel.db.aura_tracker.buff_tracked [spellId] = false + --get the spellId + local spellId = getSpellIDFromSpellName(text) + if (not spellId) then + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") + return + end + + --add the spellId to the tracklist + newAuraPanel.db.aura_tracker.buff_tracked [spellId] = false + end --refresh the buff tracklist frame newAuraPanel.buff_tracked:Refresh() diff --git a/Libs/DF/button.lua b/Libs/DF/button.lua index 99a5cbd0f..5adc8073b 100644 --- a/Libs/DF/button.lua +++ b/Libs/DF/button.lua @@ -1,4 +1,11 @@ +--[=[ + callback format: + function(button, clickType, param1, param2) + end + +--]=] + local detailsFramework = _G["DetailsFramework"] if (not detailsFramework or not DetailsFrameworkCanLoad) then @@ -304,6 +311,15 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) end end + function ButtonMetaFunctions:SetParameters(param1, param2) + if (param1 ~= nil) then + rawset(self, "param1", param1) + end + if (param2 ~= nil) then + rawset(self, "param2", param2) + end + end + ---set the text shown on the button ---@param text string function ButtonMetaFunctions:SetText(text) @@ -493,7 +509,6 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) ---enable the button making it clickable and not grayed out ---@return unknown function ButtonMetaFunctions:Enable() - return self.button:Enable() end @@ -506,6 +521,15 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) return self.button:Disable() end + ---@param enable boolean + function ButtonMetaFunctions:SetEnabled(enable) + if (enable) then + self:Enable() + else + self:Disable() + end + end + ---simulate a click on the button function ButtonMetaFunctions:Exec() local frameWidget = self.widget @@ -692,7 +716,7 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) if (object.is_mouse_over) then button.texture:SetTexCoord(unpack(button.texture.coords.Highlight)) else - button.texture:SetTexCoord(unpack(coords.Normal)) + --button.texture:SetTexCoord(unpack(coords.Normal)) end else if (object.is_mouse_over) then @@ -895,6 +919,7 @@ end ---@field Exec fun(self: df_button) execute the button function for the left button ---@field Disable fun(self: df_button) disable the button ---@field Enable fun(self: df_button) enable the button + ---@field SetEnabled fun(self: df_button, enable: boolean) enable or disable the button ---@field IsEnabled fun(self: df_button) : boolean returns true if the button is enabled ---@field SetIcon fun(self: df_button,texture: string|number, width: number|nil, height: number|nil, layout: string|nil, texcoord: table|nil, overlay: table|nil, textDistance: number|nil, leftPadding: number|nil, textHeight: number|nil, shortMethod: any|nil) ---@field GetIconTexture fun(self: df_button) : string returns the texture path of the button icon @@ -904,6 +929,7 @@ end ---@field SetTextColor fun(self: df_button, color: any) set the button text color ---@field SetText fun(self: df_button, text: string) set the button text ---@field SetTextTruncated fun(self: df_button, text: string, maxWidth: number) set the button text and truncate it if it's too long + ---@field SetParameters fun(self: df_button, param1: any, param2: any) set the parameters for the button callback function ---@field SetClickFunction fun(self: df_button, func: function, param1: any, param2: any, clickType: "left"|"right"|nil) ---@field SetIconFilterMode fun(self: df_button, filterMode: any) set the filter mode for the icon, execute after SetIcon() @@ -983,11 +1009,36 @@ end buttonObject.text_overlay = _G[name .. "_Text"] buttonObject.disabled_overlay = _G[name .. "_TextureDisabled"] + --check for atlas texture = texture or "" - buttonObject.button:SetNormalTexture(texture) - buttonObject.button:SetPushedTexture(texture) - buttonObject.button:SetDisabledTexture(texture) - buttonObject.button:SetHighlightTexture(texture, "ADD") + + local bSetTexture = false + if (type(texture) == "string") then + local isAtlas = C_Texture.GetAtlasInfo(texture) + if (isAtlas) then + buttonObject.button:SetNormalTexture("") + buttonObject.button:GetNormalTexture():SetAtlas(texture) + buttonObject.button:SetPushedTexture("") + buttonObject.button:GetPushedTexture():SetAtlas(texture) + buttonObject.button:SetDisabledTexture("") + buttonObject.button:GetDisabledTexture():SetAtlas(texture) + buttonObject.button:SetHighlightTexture("") + buttonObject.button:GetHighlightTexture():SetAtlas(texture) + bSetTexture = true + + elseif (detailsFramework:IsHtmlColor(texture)) then + local r, g, b, a = detailsFramework:ParseColors(texture) + self.icon:SetColorTexture(r, g, b, a) + bSetTexture = true + end + end + + if (not bSetTexture) then + buttonObject.button:SetNormalTexture(texture) + buttonObject.button:SetPushedTexture(texture) + buttonObject.button:SetDisabledTexture(texture) + buttonObject.button:SetHighlightTexture(texture, "ADD") + end local locTable = text detailsFramework.Language.SetTextWithLocTableWithDefault(buttonObject.button.text, locTable, text) diff --git a/Libs/DF/definitions.lua b/Libs/DF/definitions.lua index 8b332cdcd..8f358256a 100644 --- a/Libs/DF/definitions.lua +++ b/Libs/DF/definitions.lua @@ -123,6 +123,7 @@ ---@class detailsframework ---@field dversion number +---@field OnLoginSchedules function[] ---@field internalFunctions table ---@field OptionsFunctions df_optionsmixin ---@field GlobalWidgetControlNames table @@ -131,6 +132,7 @@ ---@field Schedules df_schedule ---@field HeaderFunctions df_headerfunctions ---@field Language df_language +---@field Ejc df_ejc ---@field KeybindMixin df_keybindmixin ---@field ScriptHookMixin df_scripthookmixin ---@field EditorMixin df_editormixin @@ -202,7 +204,7 @@ ---@field GetDefaultBackdropColor fun(self:table) : red, green, blue, alpha return the standard backdrop color used by blizzard on their own frames ---@field Msg fun(self:table, message:string, ...) show a message in the chat frame ---@field MsgWarning fun(self:table, message:string, ...) show a warning message in the chat frame ----@field CreateButton fun(self:table, parent:frame, func:function, width:number, height:number, text:any, param1:any, param2:any, texture:atlasname|texturepath|textureid|nil, member:string?, name:string?, shortMethod:any, buttonTemplate:table?, textTemplate:table?) : df_button +---@field CreateButton fun(self:table, parent:frame, func:function, width:number, height:number, text:any, param1:any, param2:any, texture:atlasname|texturepath|textureid|nil, member:string?, name:string?, shortMethod:any, buttonTemplate:table?, textTemplate:table?) : df_button callback function(blizzButton, clickType, param1, param2) end ---@field CreateCloseButton fun(self:table, parent:frame, frameName:string?) : df_closebutton ---@field CreateTabButton fun(self:table, parent:frame, frameName:string?) : df_tabbutton ---@field CreateRoundedPanel fun(self:table, parent:frame, frameName:string?, optionsTable:df_roundedpanel_options?) : df_roundedpanel @@ -233,16 +235,21 @@ ---@field ApplyStandardBackdrop fun(self:table, frame:frame, bUseSolidColor:boolean?, alphaScale:number?) ---@field NewLabel fun(self:table, parent:frame, container:frame, name:string?, member:string?, text:string|table, font:string?, size:any?, color:any?, layer:drawlayer?) : df_label ---@field CreateLabel fun(self:table, parent:frame, text:any, size:any?, color:any?, font:string?, member:string?, name:string?, layer:drawlayer?) : df_label +---@field NewDropDown fun(self:table, parent:frame, container:frame?, name:string?, member:string?, width:number?, height:number?, func:function, default:any, template:table?) : df_dropdown ---@field CreateDropDown fun(self:table, parent:frame, func:function, default:any, width:number?, height:number?, member:string?, name:string?, template:table?) : df_dropdown ----@field CreateFontDropDown fun(self:table, parent:frame, func:function, default:any, width:number?, height:number?, member:string?, name:string?, template:table?) : df_dropdown +---@field CreateFontDropDown fun(self:table, parent:frame, func:function, default:any, width:number?, height:number?, member:string?, name:string?, template:table?, bIncludeDefault:boolean?) : df_dropdown ---@field CreateColorDropDown fun(self:table, parent:frame, func:function, default:any, width:number?, height:number?, member:string?, name:string?, template:table?) : df_dropdown ---@field CreateOutlineDropDown fun(self:table, parent:frame, func:function, default:any, width:number?, height:number?, member:string?, name:string?, template:table?) : df_dropdown ---@field CreateAnchorPointDropDown fun(self:table, parent:frame, func:function, default:any, width:number?, height:number?, member:string?, name:string?, template:table?) : df_dropdown ---@field CreateAudioDropDown fun(self:table, parent:frame, func:function, default:any, width:number?, height:number?, member:string?, name:string?, template:table?) : df_dropdown ----@field CreateFontListGenerator fun(self:table, callback:function) : function return a function which when called returns a table filled with all fonts available and ready to be used on dropdowns +---@field CreateRaidInstanceSelectorDroDown fun(self:table, parent:frame, func:function, default:any, width:number?, height:number?, member:string?, name:string?, template:table?) : df_dropdown +---@field CreateBossSelectorDroDown fun(self:table, parent:frame, func:function, instanceId:any, default:any, width:number?, height:number?, member:string?, name:string?, template:table?) : df_dropdown_bossselector +---@field CreateFontListGenerator fun(self:table, callback:function, bIncludeDefault:boolean?) : function return a function which when called returns a table filled with all fonts available and ready to be used on dropdowns ---@field CreateAnchorPointListGenerator fun(self:table, callback:function) : function return a function which when called returns a table filled with all anchor points available and ready to be used on dropdowns ---@field CreateColorListGenerator fun(self:table, callback:function) : function return a function which when called returns a table filled with all colors available and ready to be used on dropdowns ---@field CreateOutlineListGenerator fun(self:table, callback:function) : function return a function which when called returns a table filled with all outline options available and ready to be used on dropdowns +---@field CreateBossListGenerator fun(self:table, callback:function, instanceId:any) : function return a function which when called returns a table filled with all boss options available and ready to be used on dropdowns +---@field CreateRaidInstanceListGenerator fun(self:table, callback:function) : function return a function which when called returns a table filled with all raid instance options available and ready to be used on dropdowns ---@field CreateAudioListGenerator fun(self:table, callback:function) : function return a function which when called returns a table filled with all audio options available and ready to be used on dropdowns ---@field BuildDropDownFontList fun(self:table, onClick:function, icon:atlasname|texturepath|textureid|nil, iconTexcoord:table?, iconSize:number?, bIncludeDefault:boolean?) : table build a list of fonts to be used as optionsTable for a dropdown ---@field CreateTextEntry fun(self:table, parent:frame, textChangedCallback:function, width:number, height:number, member:string?, name:string?, labelText:string?, textentryTemplate:table?, labelTemplate:table?) : df_textentry @@ -277,10 +284,10 @@ ---@field FormatColor fun(self:table, newFormat:string, r:number|string|table, g:number?, b:number?, a:number?, decimalsAmount:number?) : string|table|number|nil, number|nil, number|nil, number|nil takes in a color in one format and converts it to another specified format. ---@field CreateEditor fun(self:table, parent:frame, name:string?, options:df_editor_defaultoptions?) : df_editor ---@field RandomBool fun(self:table, odds: number?) : boolean return a random boolean ----@field CreateHighlightTexture fun(self:table, parent:frame, parentKey:string?, alpha:number?, name:string?) : texture +---@field CreateHighlightTexture fun(self:table, parent:frame, parentKey:string?, alpha:number?, name:string?, texture:any) : texture ---@field CreateIconRowGeneric fun(self:table, parent:frame, name:string?, options:table?) ---@field CreateColorPickButton fun(self:table, parent:frame, name:string?, member:string?, callback:function, alpha:number?, buttonTemplate:table?) : df_colorpickbutton ----@field CreateSlider fun(self:table, parent:frame, width:number?, height:number?, minValue:number?, maxValue:number?, step:number?, defaultv:number?, isDecemal:boolean?, member:string?, name:string?, label:string?, sliderTemplate:string|table?, labelTemplate:string|table?) : df_slider, df_label? +---@field CreateSlider fun(self:table, parent:frame, width:number?, height:number?, minValue:number?, maxValue:number?, step:number?, defaultv:number?, isDecemal:boolean?, member:string?, name:string?, label:string?, sliderTemplate:string|table?, labelTemplate:string|table?) : df_slider, df_label? When the value of the slider is changed, it'll call self.OnValueChanged if the value exists. slider.OnValueChanged = function(self, FixedValue, value) end ---@field CreateFrameContainer fun(self:table, parent:frame, options:table?, frameName:string?) : df_framecontainer create a frame container, which is a frame that envelops another frame, and can be moved, resized, etc. ---@field CreateAnimationHub fun(self:table, parent:uiobject, onPlay:function?, onFinished:function?) : animationgroup ---@field CreateAnimation fun(self:table, animationGroup:animationgroup, animationType:animationtype, order:number, duration:number, arg1:any, arg2:any, arg3:any, arg4:any, arg5:any, arg6:any, arg7:any, arg8:any) : animation @@ -336,15 +343,23 @@ ---@field CreateGraphicLineFrame fun(self:table, parent:frame, name:string) : df_chart ---@field CreateFlashAnimation fun(self:table, frame:uiobject, onFinishFunc:function?, onLoopFunc:function?) : animationgroup ---@field CreateTimeBar fun(self:table, parent:frame, texture:texturepath|textureid, width:number?, height:number?, value:number?, member:string?, name:string?) : df_timebar ----@field CreatePool fun(self:table, func:function, ...) : table ----@field CreateObjectPool fun(self:table, func:function, ...) : table alias of CreatePool +---@field CreatePool fun(self:table, func:function, ...) : df_pool +---@field CreateObjectPool fun(self:table, func:function, ...) : df_pool alias of CreatePool ---@field GetRoleIconAndCoords fun(self:table, role:string) : string, number, number, number, number return the texture path and texcoords for a role ---@field AddRoleIconToText fun(self:table, text:string, role:string, size:number?) : string add a role icon to a text using escape codes ---@field GetRoleTCoordsAndTexture fun(self:table, roleID:number) : number, number, number, number, string ---@field AddColorToText fun(self:table, text:string, color:any) : string wrap text with a color ----@field AddClassColorToText fun(self:table, text:string, className:string) : string wrap text with a class color +---@field AddClassColorToText fun(self:table, text:string, className:class) : string wrap text with a class color ---@field CreateSimplePanel fun(self:table, parent:frame, width:number?, height:number?, title:string?, frameName:string?, panelOptions:table?, savedVariableTable:table?) : simplepanel ---@field MakeDraggable fun(self:table, frame:frame) : nil +---@field CreateNewAddOn fun(self:table, addonName:string, globalSavedVariablesName:string, savedVarsTemplate:table) : table +---@field CreateBossScrollSelectorForInstance fun(self:table, instanceId:any, parent:uiobject, name:string?, options:df_bossscrollselector_options?, callback:function?, ...) : df_bossscrollselector +---@field CreateTimeLineFrame fun(self:table, parent:frame, name:string, timelineOptions:df_timeline_options, elapsedtimeOptions:df_elapsedtime_options) : df_timeline +---@field CreateElapsedTimeFrame fun(self:table, parent:frame, name:string?, options:df_elapsedtime_options?) : df_elapsedtime +---@field GetClassTCoordsAndTexture fun(self:table, class:string) : number, number, number, number, string return the class icon texture coordinates and texture file path +---@field MakeStringFromSpellId fun(self:table, spellId:any) : string return a string with the spell icon and name using escape codes +---@field AddClassIconToText fun(self:table, text:string, playerName:string, englishClassName:string, useSpec:boolean?, iconSize:number?) : string wrap 'text' with the class icon of 'playerName' using |T|t scape codes +---@field RemoveRealNameFromName fun(self:table, name:string) : string remove the realm name from a name string --[=[ diff --git a/Libs/DF/dropdown.lua b/Libs/DF/dropdown.lua index 9c95ebbd2..a91b483a9 100644 --- a/Libs/DF/dropdown.lua +++ b/Libs/DF/dropdown.lua @@ -1,4 +1,18 @@ +--[=[ + On selecting an option it calls the 'onclick' function of the option with the parameters: dropdownObject, fixedValue, option.value + Example: + + local onClickFunc = function(dropdownObject, fixedValue, value) + --fixedValue is the value set by dropdownObject:SetFixedParameter(any) + --the fixed value will be the same for any option selected in the dropdown + --do something + end + +]=] + + +---@type detailsframework local DF = _G ["DetailsFramework"] if (not DF or not DetailsFrameworkCanLoad) then return @@ -364,10 +378,7 @@ local runCallbackFunctionForButton = function(button) --exec function if any if (button.table.onclick) then --need: the the callback func, the object of the dropdown (capsule), the object (capsule) of the button to get FixedValue and the last need the value of the optionTable - local success, errorText = pcall(button.table.onclick, button:GetParent():GetParent():GetParent().MyObject, button.object.FixedValue, button.table.value) - if (not success) then - error("Details! Framework: dropdown " .. button:GetParent():GetParent():GetParent().MyObject:GetName() .. " error: " .. errorText) - end + xpcall(button.table.onclick, geterrorhandler(), button:GetParent():GetParent():GetParent().MyObject, button.object.FixedValue, button.table.value) button:GetParent():GetParent():GetParent().MyObject:RunHooksForWidget("OnOptionSelected", button:GetParent():GetParent():GetParent().MyObject, button.object.FixedValue, button.table.value) end end @@ -376,10 +387,7 @@ local canRunCallbackFunctionForOption = function(canRunCallback, optionTable, dr if (canRunCallback) then local fixedValue = rawget(dropdownObject, "FixedValue") if (optionTable.onclick) then - local success, errorText = pcall(optionTable.onclick, dropdownObject, fixedValue, optionTable.value) - if (not success) then - error("Details! Framework: dropdown " .. dropdownObject:GetName() .. " error: " .. errorText) - end + xpcall(optionTable.onclick, geterrorhandler(), dropdownObject, fixedValue, optionTable.value) dropdownObject:RunHooksForWidget("OnOptionSelected", dropdownObject, fixedValue, optionTable.value) end end @@ -1119,7 +1127,9 @@ end --object constructor ---@class df_dropdown : table, frame, df_widgets +---@field func function ---@field SetTemplate fun(self:df_dropdown, template:table|string) +---@field SetFixedParameter fun(self:df_dropdown, value:any) is sent as 2nd argument to the callback function, the value is the same no matter which option is selected ---@field BuildDropDownFontList fun(self:df_dropdown, onClick:function, icon:any, iconTexcoord:table?, iconSize:table?):table make a dropdown list with all fonts available, on select a font, call the function onClick ---@field SetFunction fun(self:df_dropdown, func:function) ---@field SetEmptyTextAndIcon fun(self:df_dropdown, text:string, icon:any) @@ -1127,6 +1137,7 @@ end ---@field Open fun(self:df_dropdown) ---@field Close fun(self:df_dropdown) ---@field Refresh fun(self:df_dropdown) +---@field GetValue fun(self:df_dropdown):any ---@field GetFunction fun(self:df_dropdown):function ---@field GetMenuSize fun(self:df_dropdown):number, number ---@field SetMenuSize fun(self:df_dropdown, width:number, height:number) @@ -1212,6 +1223,56 @@ function DF:CreateAnchorPointListGenerator(callback) return newGenerator end +function DF:CreateRaidInstanceListGenerator(callback) + ---@type df_instanceinfo[] + local allInstances = DF.Ejc.GetAllRaidInstances() + + local newGenerator = function() + local dropdownOptions = {} + + for i, instanceInfo in ipairs(allInstances) do + table.insert(dropdownOptions, { + label = instanceInfo.name, + icon = instanceInfo.icon, + texcoord = instanceInfo.iconCoords, + value = instanceInfo.journalInstanceId, + onclick = callback + }) + end + + return dropdownOptions + end + + return newGenerator +end + +function DF:CreateBossListGenerator(callback, instanceId) + ---@type df_encounterinfo[] + local allEncounters = DF.Ejc.GetAllEncountersFromInstance(instanceId) + + if (not allEncounters) then + return function() return {} end + end + + local newGenerator = function() + local dropdownOptions = {} + + for i, encounterInfo in ipairs(allEncounters) do + table.insert(dropdownOptions, { + label = encounterInfo.name, + icon = encounterInfo.creatureIcon, + texcoord = encounterInfo.creatureIconCoords, + value = encounterInfo.journalEncounterId, --use with DetailsFramework.Ejc.GetEncounterInfo(value) + onclick = callback + }) + end + + return dropdownOptions + end + + return newGenerator +end + function DF:CreateAudioListGenerator(callback) local newGenerator = function() local dropdownOptions = { @@ -1286,6 +1347,49 @@ function DF:CreateAudioDropDown(parent, callback, default, width, height, member return dropDownObject end +function DF:CreateRaidInstanceSelectorDroDown(parent, callback, default, width, height, member, name, template) + local func = DF:CreateRaidInstanceListGenerator(callback) + + ---@type df_instanceinfo[] + local allInstances = DF.Ejc.GetAllRaidInstances() + + --if an index was passed, convert it to the journalInstanceId + if (default <= #allInstances) then + default = allInstances[default].journalInstanceId + end + + --make sure the default value is valid, in a new content patch, some raids might have been reprecated from current content + if (not DF.Ejc.IsCurrentContent(default)) then + default = allInstances[1] and allInstances[1].journalInstanceId + end + + return DF:NewDropDown(parent, parent, name, member, width, height, func, default, template) +end + +---@class df_dropdown_bossselector : df_dropdown +---@field callbackFunc function +---@field SetInstance fun(self:df_dropdown_bossselector, instanceId:any) + +---@param self df_dropdown_bossselector +---@param instanceId number +local setInstance = function(self, instanceId) + self:SetFixedParameter(instanceId) + self.func = DF:CreateBossListGenerator(self.callbackFunc, instanceId) + self:Refresh() +end + +function DF:CreateBossSelectorDroDown(parent, callback, instanceId, default, width, height, member, name, template) + local func = DF:CreateBossListGenerator(callback, instanceId) + local dropdown = DF:NewDropDown(parent, parent, name, member, width, height, func, default, template) + dropdown:SetFixedParameter(instanceId) + + ---@cast dropdown +df_dropdown_bossselector + dropdown.SetInstance = setInstance + dropdown.callbackFunc = callback + + return dropdown +end + ---create a dropdown object ---@param parent frame ---@param func function @@ -1300,13 +1404,24 @@ function DF:CreateDropDown(parent, func, default, width, height, member, name, t return DF:NewDropDown(parent, parent, name, member, width, height, func, default, template) end +---create a dropdown object +---@param parent frame +---@param container frame +---@param name string? +---@param member string? +---@param width number? +---@param height number? +---@param func function +---@param default any +---@param template table? +---@return df_dropdown function DF:NewDropDown(parent, container, name, member, width, height, func, default, template) if (not name) then name = "DetailsFrameworkDropDownNumber" .. DF.DropDownCounter DF.DropDownCounter = DF.DropDownCounter + 1 elseif (not parent) then - return error("Details! Framework: parent not found.", 2) + error("Details! Framework: parent not found.", 2) end if (not container) then diff --git a/Libs/DF/ejournal.lua b/Libs/DF/ejournal.lua new file mode 100644 index 000000000..dbfb30af6 --- /dev/null +++ b/Libs/DF/ejournal.lua @@ -0,0 +1,360 @@ + +local detailsFramework = _G["DetailsFramework"] +if (not detailsFramework or not DetailsFrameworkCanLoad) then + return +end + +local defaultCreatureIconCoords = {0, 1, 0, 0.95} + +---@class df_encounterinfo : table +---@field name string +---@field mapId number +---@field instanceId number +---@field dungeonEncounterId number +---@field journalEncounterId number +---@field journalInstanceId number +---@field creatureName string +---@field creatureIcon string +---@field creatureIconCoords table +---@field creatureId number +---@field creatureDisplayId number +---@field creatureUIModelSceneId number + +---@class df_instanceinfo : table +---@field name string +---@field bgImage string +---@field mapId number +---@field instanceId number +---@field journalInstanceId number +---@field isRaid boolean +---@field encountersArray df_encounterinfo[] +---@field encountersByName table +---@field encountersByDungeonEncounterId table +---@field encountersByJournalEncounterId table +---@field icon string +---@field iconSize table +---@field iconCoords table +---@field iconLore string +---@field iconLoreSize table +---@field iconLoreCoords table +---@field iconTexture string +---@field iconTextureSize table +---@field iconTextureCoords table + +---@class df_ejc : table +---@field GetEncounterInfo fun(id:number):df_encounterinfo +---@field GetInstanceInfo fun(id:instanceid|instancename|mapid):df_instanceinfo +---@field GetInstanceEJID fun(...):number +---@field IsCurrentContent fun(id:number):boolean +---@field GetAllEncountersFromInstance fun(id:any):df_encounterinfo[] +---@field CreateEncounterJournalDump fun() +---@field GetAllRaidInstances fun():df_instanceinfo[] +---@field GetAllDungeonInstances fun():df_instanceinfo[] +---@field CacheRaidData_OnlyRaidInstances table +---@field CacheRaidData_OnlyDungeonInstances table +---@field CacheRaidData_ByInstanceId table +---@field CacheRaidData_ByInstanceName table +---@field CacheRaidData_ByMapId table +---@field CacheEncountersByEncounterName table +---@field CacheEncountersBy_EncounterName table +---@field CacheEncountersBy_EncounterId table +---@field CacheEncountersBy_JournalEncounterId table +---@field Id_To_JournalInstanceID table +---@field CurrentContent table + +local bHasLoaded = false + +if (detailsFramework.Ejc) then + wipe(detailsFramework.Ejc) +end + +detailsFramework.Ejc = {} +local Ejc = detailsFramework.Ejc + +---@return df_encounterinfo? +function Ejc.GetEncounterInfo(id) + if (not bHasLoaded) then + Ejc.CreateEncounterJournalDump() + end + + ---@type df_encounterinfo + local encounterData = Ejc.CacheEncountersBy_EncounterId[id] + if (encounterData) then + return encounterData + end + + encounterData = Ejc.CacheEncountersBy_EncounterName[id] + if (encounterData) then + return encounterData + end + + encounterData = Ejc.CacheEncountersBy_JournalEncounterId[id] + if (encounterData) then + return encounterData + end +end + +function Ejc.Load() + Ejc.CreateEncounterJournalDump() +end + +---@param id instanceid|instancename|mapid +---@return df_instanceinfo? +function Ejc.GetInstanceInfo(id) + if (not id) then + return + end + + if (not bHasLoaded) then + Ejc.CreateEncounterJournalDump() + end + + if (id == 463) then --fall + id = 1209 + end + + ---@type df_instanceinfo + local instanceData = Ejc.CacheRaidData_ByInstanceId[id] + if (instanceData) then + return instanceData + end + + instanceData = Ejc.CacheRaidData_ByInstanceName[id] + if (instanceData) then + return instanceData + end + + instanceData = Ejc.CacheRaidData_ByMapId[id] + if (instanceData) then + return instanceData + end +end + +function Ejc.GetInstanceEJID(...) + for i = 1, select("#", ...) do + local id = select(i, ...) + local EJID = Ejc.Id_To_JournalInstanceID[id] + if (EJID) then + return EJID + end + end +end + +function Ejc.IsCurrentContent(id) + return Ejc.CurrentContent[id] +end + +function Ejc.GetAllEncountersFromInstance(id) + if (not bHasLoaded) then + Ejc.CreateEncounterJournalDump() + end + + local instanceData = Ejc.GetInstanceInfo(id) + if (instanceData) then + return instanceData.encountersArray + end +end + +function Ejc.GetAllRaidInstances() + if (not bHasLoaded) then + Ejc.CreateEncounterJournalDump() + end + return Ejc.CacheRaidData_OnlyRaidInstances +end + +function Ejc.GetAllDungeonInstances() + if (not bHasLoaded) then + Ejc.CreateEncounterJournalDump() + end + return Ejc.CacheRaidData_OnlyDungeonInstances +end + +function Ejc.CreateEncounterJournalDump() + --if the cache has been already created, then return + if (bHasLoaded) then + return + else + bHasLoaded = true + end + + --this table store ids which indicates the bossId, encounterId or mapId is a content from the current expansion + Ejc.CurrentContent = {} + + Ejc.CacheRaidData_ByInstanceId = {} + Ejc.CacheRaidData_ByInstanceName = {} --this is localized name + Ejc.CacheRaidData_ByMapId = {} --retrivied from GetInstanceInfo() + Ejc.CacheEncountersByEncounterName = {} + Ejc.CacheEncountersBy_EncounterName = {} + Ejc.CacheEncountersBy_EncounterId = {} + Ejc.CacheEncountersBy_JournalEncounterId = {} + Ejc.CacheRaidData_OnlyRaidInstances = {} + Ejc.CacheRaidData_OnlyDungeonInstances = {} + + ---cahe the uiMapID pointing to the instanceID + ---this replace the need to call EJ_GetInstanceForMap to get the journalInstanceID + ---@type table + local id_to_journalInstanceID = {} + Ejc.Id_To_JournalInstanceID = id_to_journalInstanceID + + --if the expansion does not support the encounter journal, then return + if (not EncounterJournal_LoadUI) then + return + end + + local data = {} + + ---returns the number of valid encounter journal tier indices + ---@type number + local tierAmount = EJ_GetNumTiers() --return 11 for dragonisles, is returning 11 for wow11 as well + + ---returns the currently active encounter journal tier index + ---could also be tierAmount - 1 + ---because the tier is "current season" + ---@type number + local currentTierId = tierAmount --EJ_GetCurrentTier(), for some unknown reason, this function is returning 3 on retail + + ---maximum amount of dungeons in the expansion + ---@type number + local maxAmountOfDungeons = 20 + + ---the index of the first raid tier in the expansion, ignoring the first tier as it is open world bosses + ---@type number + local raidTierStartIndex = 2 + + ---max amount of bosses which a raid tier can have + ---@type number + local maxRaidBosses = 20 + + ---two iterations are required, one for dungeons and another for raids + ---this table store two booleans that are passed to EJ_GetInstanceByIndex second argument, to indicate if we want to get dungeons or raids + local tGetDungeonsOrRaids = {false, true} + + do --get raid instances data + for i = 1, #tGetDungeonsOrRaids do + local bIsRaid = tGetDungeonsOrRaids[i] + + --select the tier, use current tier - 1 for raids, as the currentTier only shows the latest release raid + --use current tier for dungeons, as the current tier shows the dungeons used for the current season of Mythic+ + local startIndex, endIndex + if (bIsRaid) then + if (detailsFramework.IsCataWow()) then + if (currentTierId == 1) then --Cata has only one tier. Looking up tier 0 errors. ~CATA + break + end + end + + EJ_SelectTier(currentTierId) --print("tier selected:", currentTierId - 1, "raids") --debug: was (currentTierId - 1), but was selecting wow10 content + startIndex = raidTierStartIndex + endIndex = 20 + else + EJ_SelectTier(currentTierId) --print("tier selected:", currentTierId, "dungeons", "currentTierId:", currentTierId) --debug + startIndex = 1 + endIndex = maxAmountOfDungeons + end + + for instanceIndex = endIndex, startIndex, -1 do + --instanceID: number - the unique ID of the instance, also returned by GetInstanceInfo() 8th return value + --journalInstanceID: number - the ID used by the Encounter Journal API + --dungeonUiMapID: number - the ID used by the world map API + --dungeonEncounterID: number - same ID passed by the ENCOUNTER_STAR and ENCOUNTER_END events + local journalInstanceID, instanceName, description, bgImage, buttonImage1, loreImage, buttonImage2, dungeonUiMapID, journalLink, shouldDisplayDifficulty, instanceID = EJ_GetInstanceByIndex(instanceIndex, bIsRaid) + + if (journalInstanceID) then + id_to_journalInstanceID[dungeonUiMapID] = journalInstanceID + id_to_journalInstanceID[instanceName] = journalInstanceID + id_to_journalInstanceID[instanceID] = journalInstanceID + + Ejc.CurrentContent[journalInstanceID] = true + Ejc.CurrentContent[dungeonUiMapID] = true + Ejc.CurrentContent[instanceID] = true + Ejc.CurrentContent[instanceName] = true + + --select the raid instance, this allow to retrieve data about the encounters of the instance + EJ_SelectInstance(journalInstanceID) + + --build a table with data of the raid instance + local instanceData = { + name = instanceName, + bgImage = bgImage, + mapId = dungeonUiMapID, + instanceId = instanceID, + journalInstanceId = journalInstanceID, + isRaid = bIsRaid, + + encountersArray = {}, + encountersByName = {}, + encountersByDungeonEncounterId = {}, + encountersByJournalEncounterId = {}, + + icon = buttonImage1, + iconSize = {70, 36}, + iconCoords = {0.01, .67, 0.025, .725}, + + iconLore = loreImage, + iconLoreSize = {70, 36}, + iconLoreCoords = {0, 1, 0, 0.95}, + + iconTexture = buttonImage2, + iconTextureSize = {70, 36}, + iconTextureCoords = {0, 1, 0, 0.95}, + } + + --cache the raidData, in different tables, using different keys + Ejc.CacheRaidData_ByInstanceId[journalInstanceID] = instanceData + Ejc.CacheRaidData_ByInstanceId[instanceID] = instanceData + Ejc.CacheRaidData_ByInstanceName[instanceName] = instanceData + Ejc.CacheRaidData_ByMapId[dungeonUiMapID] = instanceData + + if (bIsRaid) then + Ejc.CacheRaidData_OnlyRaidInstances[#Ejc.CacheRaidData_OnlyRaidInstances+1] = instanceData + else + Ejc.CacheRaidData_OnlyDungeonInstances[#Ejc.CacheRaidData_OnlyDungeonInstances+1] = instanceData + end + + --get information about the bosses in the raid + for encounterIndex = 1, maxRaidBosses do + local encounterName, encounterDescription, journalEncounterID, rootSectionID, link, journalInstanceID, dungeonEncounterID, instanceID = EJ_GetEncounterInfoByIndex(encounterIndex, journalInstanceID) + + if (encounterName) then + local encounterData = { + name = encounterName, + mapId = dungeonUiMapID, + instanceId = instanceID, + dungeonEncounterId = dungeonEncounterID, + journalEncounterId = journalEncounterID, + journalInstanceId = journalInstanceID, + } + + Ejc.CurrentContent[encounterName] = true + Ejc.CurrentContent[journalEncounterID] = true + Ejc.CurrentContent[dungeonEncounterID] = true + + local journalEncounterCreatureId, creatureName, creatureDescription, creatureDisplayID, iconImage, uiModelSceneID = EJ_GetCreatureInfo(1, journalEncounterID) + if (journalEncounterCreatureId) then + encounterData.creatureName = creatureName + encounterData.creatureIcon = iconImage + encounterData.creatureIconCoords = defaultCreatureIconCoords + encounterData.creatureId = journalEncounterCreatureId + encounterData.creatureDisplayId = creatureDisplayID + encounterData.creatureUIModelSceneId = uiModelSceneID + end + + instanceData.encountersArray[#instanceData.encountersArray+1] = encounterData + instanceData.encountersByName[encounterName] = encounterData + --print(instanceName, encounterName, journalEncounterID, journalInstanceID, dungeonEncounterID, instanceID) + instanceData.encountersByDungeonEncounterId[dungeonEncounterID] = encounterData + instanceData.encountersByJournalEncounterId[journalEncounterID] = encounterData + Ejc.CacheEncountersBy_EncounterName[encounterName] = encounterData + Ejc.CacheEncountersBy_EncounterId[dungeonEncounterID] = encounterData + Ejc.CacheEncountersBy_JournalEncounterId[journalEncounterID] = encounterData + + id_to_journalInstanceID[encounterName] = journalInstanceID + id_to_journalInstanceID[dungeonEncounterID] = journalInstanceID + id_to_journalInstanceID[journalEncounterID] = journalInstanceID + end + end + end + end + end + end +end \ No newline at end of file diff --git a/Libs/DF/elapsedtime.lua b/Libs/DF/elapsedtime.lua new file mode 100644 index 000000000..2066d8b56 --- /dev/null +++ b/Libs/DF/elapsedtime.lua @@ -0,0 +1,152 @@ + +local detailsFramework = _G ["DetailsFramework"] +if (not detailsFramework or not DetailsFrameworkCanLoad) then + return +end + +local _ + + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +--horizontal bar with 20 pixels height with many texts indicating the time in seconds, example: 0:10, 0:30, 1:45, 2:00, 2:30, 3:00, 3:30, 4:00 + +---@class df_elapsedtime_options : table +---@field backdrop backdrop +---@field backdrop_color number[] +---@field text_color number[] +---@field text_size number +---@field text_font string +---@field text_outline outline +---@field height number +---@field distance number +---@field distance_min number +---@field draw_line boolean +---@field draw_line_color number[] +---@field draw_line_thickness number +local elapsedtime_frame_options = { + backdrop = {bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}, + backdrop_color = {.3, .3, .3, .7}, + + text_color = {1, 1, 1, 1}, + text_size = 12, + text_font = "Arial Narrow", + text_outline = "NONE", + + height = 20, + + distance = 200, --distance in pixels between each label informing the time + distance_min = 50, --minimum distance in pixels + draw_line = true, --if true it'll draw a vertical line to represent a segment + draw_line_color = {1, 1, 1, 0.2}, + draw_line_thickness = 1, +} + +---@class df_elapsedtime_label : fontstring +---@field line texture + +---@class df_elapsedtime_mixin : table +---@field GetLabel fun(self:df_elapsedtime, index:number):fontstring +---@field Reset fun(self:df_elapsedtime) +---@field Refresh fun(self:df_elapsedtime, elapsedTime:number, scale:number) +detailsFramework.TimeLineElapsedTimeFunctions = { + --get a label and update its appearance + GetLabel = function(self, index) + ---@type df_elapsedtime_label + local label = self.labels[index] + + if (not label) then + ---@diagnostic disable-next-line: cast-local-type + label = self:CreateFontString(nil, "artwork", "GameFontNormal") + ---@cast label df_elapsedtime_label + label.line = self:CreateTexture(nil, "artwork") + label.line:SetColorTexture(1, 1, 1) + label.line:SetPoint("topleft", label, "bottomleft", 0, -2) + self.labels[index] = label + end + + detailsFramework:SetFontColor(label, self.options.text_color) + detailsFramework:SetFontSize(label, self.options.text_size) + detailsFramework:SetFontFace(label, self.options.text_font) + detailsFramework:SetFontOutline(label, self.options.text_outline) + + if (self.options.draw_line) then + label.line:SetVertexColor(unpack(self.options.draw_line_color)) + label.line:SetWidth(self.options.draw_line_thickness) + label.line:Show() + else + label.line:Hide() + end + + return label + end, + + Reset = function(self) + for i = 1, #self.labels do + self.labels[i]:Hide() + end + end, + + Refresh = function(self, elapsedTime, scale) + if (not elapsedTime) then + --invalid data passed + return + end + + local parent = self:GetParent() + + self:SetHeight(self.options.height) + local effectiveArea = self:GetWidth() --already scaled down width + local pixelPerSecond = elapsedTime / effectiveArea --how much 1 pixels correlate to time + + local distance = self.options.distance --pixels between each segment + local minDistance = self.options.distance_min --min pixels between each segment + + --scale the distance between each label showing the time with the parent's scale + distance = distance * scale + distance = max(distance, minDistance) + + local amountSegments = ceil (effectiveArea / distance) + + for i = 1, amountSegments do + local label = self:GetLabel(i) + ---@cast label df_elapsedtime_label + local xOffset = distance * (i - 1) + label:SetPoint("left", self, "left", xOffset, 0) + + local secondsOfTime = pixelPerSecond * xOffset + + label:SetText(detailsFramework:IntegerToTimer(floor(secondsOfTime))) + + if (label.line:IsShown()) then + label.line:SetHeight(parent:GetParent():GetHeight()) + end + + label:Show() + end + end, +} + +---@class df_elapsedtime : frame, df_elapsedtime_mixin, df_optionsmixin +---@field labels table + +---creates a frame to show the elapsed time in a row +---@param parent frame +---@param name string? +---@param options df_elapsedtime_options? +---@return df_elapsedtime +function detailsFramework:CreateElapsedTimeFrame(parent, name, options) + local elapsedTimeFrame = CreateFrame("frame", name, parent, "BackdropTemplate") + + detailsFramework:Mixin(elapsedTimeFrame, detailsFramework.OptionsFunctions) + detailsFramework:Mixin(elapsedTimeFrame, detailsFramework.LayoutFrame) + detailsFramework:Mixin(elapsedTimeFrame, detailsFramework.TimeLineElapsedTimeFunctions) + + elapsedTimeFrame:BuildOptionsTable(elapsedtime_frame_options, options) + + elapsedTimeFrame:SetBackdrop(elapsedTimeFrame.options.backdrop) + elapsedTimeFrame:SetBackdropColor(unpack(elapsedTimeFrame.options.backdrop_color)) + + elapsedTimeFrame.labels = {} + + return elapsedTimeFrame +end \ No newline at end of file diff --git a/Libs/DF/fw.lua b/Libs/DF/fw.lua index 0fda4ed5e..45fd0d400 100644 --- a/Libs/DF/fw.lua +++ b/Libs/DF/fw.lua @@ -1,6 +1,6 @@ -local dversion = 572 +local dversion = 574 local major, minor = "DetailsFramework-1.0", dversion local DF, oldminor = LibStub:NewLibrary(major, minor) @@ -15,6 +15,20 @@ _G["DetailsFramework"] = DF local detailsFramework = DF +--store functions to call when the PLAYER_LOGIN event is triggered +detailsFramework.OnLoginSchedules = {} +local dfFrame = CreateFrame("frame") +dfFrame:RegisterEvent("PLAYER_LOGIN") +dfFrame:SetScript("OnEvent", function(self, event, ...) + if (event == "PLAYER_LOGIN") then + C_Timer.After(0, function() + for _, func in ipairs(detailsFramework.OnLoginSchedules) do + func() + end + end) + end +end) + DetailsFrameworkCanLoad = true local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0") @@ -1354,7 +1368,7 @@ end ---receives a string 'text' and a class name and return the string wrapped with the class color using |c and |r scape codes ---@param self table ---@param text string ----@param className string +---@param className class ---@return string function DF:AddClassColorToText(text, className) if (type(className) ~= "string") then @@ -2935,7 +2949,7 @@ DF.font_templates["ORANGE_FONT_TEMPLATE"] = {color = {1, 0.8235, 0, 1}, size = 1 --DF.font_templates["OPTIONS_FONT_TEMPLATE"] = {color = "yellow", size = 9.6, font = DF:GetBestFontForLanguage()} DF.font_templates["OPTIONS_FONT_TEMPLATE"] = {color = {1, 1, 1, 0.9}, size = 9.6, font = DF:GetBestFontForLanguage()} DF.font_templates["SMALL_SILVER"] = {color = "silver", size = 9, font = DF:GetBestFontForLanguage()} - +--~templates --dropdowns DF.dropdown_templates = DF.dropdown_templates or {} DF.dropdown_templates["OPTIONS_DROPDOWN_TEMPLATE"] = { @@ -4668,13 +4682,7 @@ function DF:QuickDispatch(func, ...) return end - local okay, errortext = xpcall(func, geterrorhandler(), ...) - - if (not okay) then - --trigger an error msg - dispatch_error(_, errortext) - return - end + xpcall(func, geterrorhandler(), ...) return true end @@ -5477,7 +5485,15 @@ do end local get_all_inuse = function(self) - return self.inUse; + return self.inUse + end + + local sort = function(self, func) + if (not func) then + table.sort(self.inUse, self.sortFunc) + elseif (func) then + table.sort(self.inUse, func) + end end local release = function(self, object) @@ -5529,6 +5545,7 @@ do ---@field inUse table[] --objects in use ---@field notUse table[] --objects not in use ---@field payload table --payload to be sent to the newObjectFunc + ---@field sortFunc fun(a:table, b:table):boolean --sort function ---@field onRelease fun(object:table) --function to be called when an object is released ---@field onReset fun(object:table) --function to be called when the pool is reset ---@field onAcquire fun(object:table) --function to be called when an object is acquired @@ -5550,6 +5567,7 @@ do ---@field SetOnAcquire fun(self:df_pool, func:fun(object:table)) --set a function to be called when an object is acquired ---@field SetCallbackOnGet fun(self:df_pool, func:fun(object:table)) --alias for :SetOnAcquire() ---@field RunForInUse fun(self:df_pool, func:fun(object:table)) --run a function for each object in use + ---@field Sort fun(self:df_pool, func:function?) --sort the objects in use local poolMixin = { Get = get, GetAllInUse = get_all_inuse, @@ -5560,6 +5578,11 @@ do Hide = hide, Show = show, GetAmount = getamount, + Sort = sort, + + SetSortFunction = function(self, func) + self.sortFunc = func + end, SetOnRelease = function(self, func) self.onRelease = func @@ -5600,6 +5623,7 @@ do DF.PoolMixin = poolMixin + --~pool function DF:CreatePool(func, ...) local newPool = {} DetailsFramework:Mixin(newPool, poolMixin) @@ -5614,6 +5638,162 @@ do end +----------------------------------------------------------------------------------------------------------------------------------------------------------- +---bossmobs + +DETAILSFRAMEWORK_TIMEBARCACHE = {} + +--register phase +function DF:RegisterEncounterPhaseChange(func, ...) + if (not DETAILSFRAMEWORK_PHASECALLBACKS) then + DETAILSFRAMEWORK_PHASECALLBACKS = {} + end + table.insert(DETAILSFRAMEWORK_PHASECALLBACKS, {callback = func, payload = {...}}) +end + +--DF:RegisterEncounterPhaseChange(function(...)print("PHASE CHANGED", ...)end, "my payload!") + +--unregister phase +function DF:UnregisterEncounterPhaseChange(func) + if (DETAILSFRAMEWORK_PHASECALLBACKS) then + for i = #DETAILSFRAMEWORK_PHASECALLBACKS, 1, -1 do + if (DETAILSFRAMEWORK_PHASECALLBACKS[i].callback == func) then + table.remove(DETAILSFRAMEWORK_PHASECALLBACKS, i) + end + end + end +end + +local sendPhaseNotification = function(phaseId) + if (DETAILSFRAMEWORK_PHASECALLBACKS) then + for _, data in ipairs(DETAILSFRAMEWORK_PHASECALLBACKS) do + DF:Dispatch(data.callback, phaseId, unpack(data.payload)) + end + end +end + +--register time bar +function DF:RegisterEncounterTimeBar(func, ...) + if (not DETAILSFRAMEWORK_TIMEBARCALLBACKS) then + DETAILSFRAMEWORK_TIMEBARCALLBACKS = {} + end + table.insert(DETAILSFRAMEWORK_TIMEBARCALLBACKS, {callback = func, payload = {...}}) +end + +--DF:RegisterEncounterTimeBar(function(...) DETAILSFRAMEWORK_TIMEBARCACHE[#DETAILSFRAMEWORK_TIMEBARCACHE+1] = {...} end) + +--[=[ +bigwigs +table: 0000019DA5382410 BigWigs_StartBar table: 0000019EF3E5B910 441362 Volatile Concoction: Jieon* 8 136227 false nil +table: 0000019DA5382410 BigWigs_StartBar table: 0000019EF3E5B910 443274 Swirls (30) 7.5 538040 false nil +]=] + +--unregister time bar +function DF:UnregisterEncounterTimeBar(func) + if (DETAILSFRAMEWORK_TIMEBARCALLBACKS) then + for i = #DETAILSFRAMEWORK_TIMEBARCALLBACKS, 1, -1 do + if (DETAILSFRAMEWORK_TIMEBARCALLBACKS[i].callback == func) then + table.remove(DETAILSFRAMEWORK_TIMEBARCALLBACKS, i) + end + end + end +end + +local sendTimeBarNotification = function(token, barType, id, msg, timer, icon, spellId, colorId, modid) + if (DETAILSFRAMEWORK_TIMEBARCALLBACKS) then + for _, data in ipairs(DETAILSFRAMEWORK_TIMEBARCALLBACKS) do + DF:Dispatch(data.callback, token, barType, id, msg, timer, icon, spellId, colorId, modid, unpack(data.payload)) + end + end +end + +local createBossModsCallback = function() + if (_G.DBM) then + local DBM = _G.DBM + + --phase change + local phaseChangeCallback = function(event, mod, modId, phase, encounterId, stageTotal) + sendPhaseNotification(phase) + end + DBM:RegisterCallback("DBM_SetStage", phaseChangeCallback) + + --time bars + local timerChangeCallback = function(bar_type, id, msg, timer, icon, bartype, spellId, colorId, modid) + local currentCombat = Details:GetCurrentCombat() + if (not currentCombat.__destroyed) then --async events, need to check for combat destruction + ---@type combattime + local combatTime = currentCombat:GetCombatTime() + table.insert(currentCombat.bossTimers, {"dbm", combatTime, bar_type, id, msg, timer, icon, bartype, spellId, colorId, modid}) + --print("dbm event", bar_type, id, msg, timer, icon, bartype, spellId, colorId, modid) + + local spell = tostring(spellId) + if (spell and not current_table_dbm[spell]) then + current_table_dbm[spell] = {spell, id, msg, timer, icon, bartype, spellId, colorId, modid} + end + end + end + + DBM:RegisterCallback("DBM_TimerStart", timerChangeCallback) + end + + local BigWigsLoader = BigWigsLoader + + if (BigWigsLoader and not _G.DBM) then + --Bigwigs change the phase of an encounter + if (BigWigsLoader.RegisterMessage) then + local t = {} + t.BigWigs_SetStage = function(self, event, module, phase) + phase = tonumber(phase) + sendPhaseNotification(phase) + end + BigWigsLoader.RegisterMessage(t, "BigWigs_SetStage") + end + + if (BigWigsLoader.RegisterMessage) then + local t = {} + t.BigWigs_StartBar = function(self, event, module, spellId, barText, barTime, iconTexture, ...) + --table: 0000019DA5382410 BigWigs_StartBar table: 0000019EF3E5B910 441362 Volatile Concoction (14) 20 136227 false nil + --print("START", self, event, module, spellId, ...) + sendTimeBarNotification("START", spellId, barText, barTime, iconTexture, ...) + end + + t.BigWigs_StopBar = function(self, event, module, spellId, ...) + --print("BW STOP BAR", self, event, module, spellId, ...) + sendTimeBarNotification("STOP", spellId) + end + + t.BigWigs_StopBars = function(self, event, module, ...) + --print("BW STOP BARS", self, event, module, ...) + sendTimeBarNotification("STOPALL") + end + + t.BigWigs_PauseBar = function(self, event, module, spellId, ...) + --print("BW PAUSE BAR", self, event, module, spellId, ...) + sendTimeBarNotification("PAUSE", spellId) + end + + t.BigWigs_ResumeBar = function(self, event, module, spellId, ...) + --print("BW RESUME BAR", self, event, module, spellId, ...) + sendTimeBarNotification("RESUME", spellId) + end + + BigWigsLoader.RegisterMessage(t, "BigWigs_StartBar") + BigWigsLoader.RegisterMessage(t, "BigWigs_StopBar") + BigWigsLoader.RegisterMessage(t, "BigWigs_StopBars") + BigWigsLoader.RegisterMessage(t, "BigWigs_PauseBar") + BigWigsLoader.RegisterMessage(t, "BigWigs_ResumeBar") + + --self:RegisterMessage("BigWigs_StopBars", "StopModuleBars") + end + end +end + + + +detailsFramework.OnLoginSchedules[#detailsFramework.OnLoginSchedules+1] = createBossModsCallback + + + ----------------------------------------------------------------------------------------------------------------------------------------------------------- --forbidden functions on scripts diff --git a/Libs/DF/line_indicator.lua b/Libs/DF/line_indicator.lua new file mode 100644 index 000000000..1bdba4416 --- /dev/null +++ b/Libs/DF/line_indicator.lua @@ -0,0 +1,467 @@ + +local detailsFramework = _G ["DetailsFramework"] +if (not detailsFramework or not DetailsFrameworkCanLoad) then + return +end + +local _ + +---@class df_lineindicator_data : table +---@field value number +---@field valueType "PERCENT"|"TIME"|"PIXELS" +---@field width number +---@field color number[] +---@field alpha number +---@field onClick fun(self:df_lineindicator_line) +---@field onEnter fun(self:df_lineindicator_line) +---@field onLeave fun(self:df_lineindicator_line) + +---@class df_lineindicator_line : button +---@field xOffset number +---@field left number +---@field index number +---@field data df_lineindicator_data +---@field Texture texture + +---@param self df_lineindicator +---@param indicator df_lineindicator_line +local lineIndicator_GetValueForMoving = function(self, indicator, leftDiff) + local targetFrame = self:LineIndicatorGetTarget() + local data = indicator.data + + if (data.valueType == "PERCENT") then + local effectiveWidth = targetFrame:GetWidth() - self.lineIndicatorXOffset + local x = indicator:GetLeft() - self.lineIndicatorXOffset + local percent = x / effectiveWidth + data.value = percent + return data.value + + elseif (data.valueType == "TIME") then + local pixelPerSecond = self.lineIndicatorPixelPerSecond + + if (leftDiff) then --leftDiff is the amount of pixels the indicator has moved + --scale the pixels per second with the scale set + pixelPerSecond = pixelPerSecond * self.lineIndicatorScale + --get the time difference in seconds by dividing the pixels moved by the pixels per second + local timeDiff = leftDiff / pixelPerSecond + --add the time difference to the current value + data.value = data.value + timeDiff + return data.value + else + local effectiveWidth = targetFrame:GetWidth() - self.lineIndicatorXOffset + local indicatorXOffset = indicator:GetLeft() - self.lineIndicatorXOffset + local timePercent = indicatorXOffset / effectiveWidth + data.value = timePercent * self.lineIndicatorTotalTime + return data.value + end + + elseif (data.valueType == "PIXELS") then + local x = indicator:GetLeft() - self.lineIndicatorXOffset + data.value = x + return data.value + end +end + +---@class df_lineindicator : table, frame +---@field lineIndicatorTotalTime number +---@field lineIndicatorXOffset number +---@field lineIndicators df_pool +---@field lineIndicatorData table +---@field lineIndicatorValueType string +---@field lineIndicatorFrameTarget frame +---@field lineIndicatorScale number +---@field lineIndicatorLineHeight number +---@field lineIndicatorLineWidth number +---@field lineIndicatorPixelPerSecond number +---@field lineIndicatorColor any +---@field lineIndicatorValueFontString fontstring +---@field LineIndicatorConstructor fun(self:df_lineindicator) +---@field LineIndicatorSetTarget fun(self:df_lineindicator, frameTarget:frame) +---@field LineIndicatorsReset fun(self:df_lineindicator) +---@field LineIndicatorCreateLine fun(self:df_lineindicator, index:number):df_lineindicator_line +---@field LineIndicatorGetLine fun(self:df_lineindicator):df_lineindicator_line +---@field LineIndicatorSetElapsedTime fun(self:df_lineindicator, totalTime:number) +---@field LineIndicatorSetLinePosition fun(self:df_lineindicator, line:df_lineindicator_line, value:number, valueType:string) +---@field LineIndicatorSetValueType fun(self:df_lineindicator, valueType:"PERCENT"|"TIME"|"PIXELS") +---@field LineIndicatorAddData fun(self:df_lineindicator, data:df_lineindicator_data) +---@field LineIndicatorSetData fun(self:df_lineindicator, data:df_lineindicator_data[]) +---@field LineIndicatorRemoveData fun(self:df_lineindicator, dataId:number|df_lineindicator_data) +---@field LineIndicatorAddLine fun(self:df_lineindicator, value:number, valueType:string) : df_lineindicator_line +---@field LineIndicatorSetXOffset fun(self:df_lineindicator, xOffset:number) +---@field LineIndicatorSetScale fun(self:df_lineindicator, scale:number) +---@field LineIndicatorRefresh fun(self:df_lineindicator) +---@field LineIndicatorSetAllLinesWidth fun(self:df_lineindicator, width:number) +---@field LineIndicatorSetAllLinesHeight fun(self:df_lineindicator, height:number) set the height of all lines +---@field LineIndicatorSetAllLinesColor fun(self:df_lineindicator, color:any, g:number?, b:number?) +---@field LineIndicatorSetLineWidth fun(self:df_lineindicator, dataId:number|df_lineindicator_data, newWidth:number) +---@field LineIndicatorSetLineColor fun(self:df_lineindicator, dataId:number|df_lineindicator_data, color:any, g:number?, b:number?) +---@field LineIndicatorSetLineAlpha fun(self:df_lineindicator, dataId:number|df_lineindicator_data, alpha:number) +---@field LineIndicatorGetTarget fun(self:df_lineindicator):frame +---@field LineIndicatorSetPixelsPerSecond fun(self:df_lineindicator, pixelsPerSecond:number) +detailsFramework.LineIndicatorMixin = { + LineIndicatorConstructor = function(self) + self.lineIndicatorTotalTime = 0 + self.lineIndicators = detailsFramework:CreatePool(detailsFramework.LineIndicatorMixin.LineIndicatorCreateLine, self) + self.lineIndicators:SetOnReset(function(lineIndicator) lineIndicator:Hide() lineIndicator:ClearAllPoints() end) + self.lineIndicatorFrameTarget = nil + self.lineIndicatorData = {} + self.lineIndicatorValueType = "PIXELS" + self.lineIndicatorXOffset = 0 + self.lineIndicatorScale = 1 + self.lineIndicatorLineHeight = 50 + self.lineIndicatorLineWidth = 3 + self.lineIndicatorColor = {1, 1, 1} + self.lineIndicatorPixelPerSecond = 20 + self.lineIndicatorMouseEnabled = true + end, + + LineIndicatorSetTarget = function(self, frameTarget) + self.lineIndicatorFrameTarget = frameTarget + end, + + LineIndicatorGetTarget = function(self) + return self.lineIndicatorFrameTarget or self + end, + + LineIndicatorSetPixelsPerSecond = function(self, pixelsPerSecond) + self.lineIndicatorPixelPerSecond = pixelsPerSecond + end, + + --hide all indicators and clear their points + ---@param self df_lineindicator + LineIndicatorsReset = function(self) + self.lineIndicatorTotalTime = 0 + self.lineIndicators:Reset() + end, + + ---@param pool df_pool + ---@param self df_lineindicator + ---@return df_lineindicator_line + LineIndicatorCreateLine = function(pool, self) + local index = pool:GetAmount() + 1 + local parentName = self:GetName() + local indicatorName = parentName and parentName .. "LineIndicator" .. index + + local targetFrame = self:LineIndicatorGetTarget() + + ---@type df_lineindicator_line + local indicator = CreateFrame("button", indicatorName, targetFrame, "BackdropTemplate") + indicator:SetSize(3, targetFrame:GetParent():GetHeight()) + indicator:SetFrameLevel(targetFrame:GetFrameLevel() + 10) + + local texture = indicator:CreateTexture(nil, "background") + texture:SetColorTexture(1, 1, 1, 1) + texture:SetAllPoints() + + indicator:SetMovable(true) + indicator:RegisterForDrag("LeftButton") + + indicator:SetScript("OnMouseDown", function() + indicator.left = indicator:GetLeft() + end) + + indicator:SetScript("OnDragStart", function() + indicator:StartMoving() + indicator:SetUserPlaced(false) + + if (not self.lineIndicatorValueFrame) then + self.lineIndicatorValueFrame = CreateFrame("frame", nil, self) + self.lineIndicatorValueFrame:SetSize(100, 20) + self.lineIndicatorValueFrame:SetFrameLevel(self:GetFrameLevel() + 11) + + local valueString = self.lineIndicatorValueFrame:CreateFontString(nil, "overlay", "GameFontNormal") + valueString:SetPoint("left", self.lineIndicatorValueFrame, "left", 2, 0) + self.lineIndicatorValueFrame.lineIndicatorValueFontString = valueString + + valueString.Background = self.lineIndicatorValueFrame:CreateTexture(nil, "artwork") + valueString.Background:SetColorTexture(0, 0, 0, 0.7) + valueString.Background:SetPoint("topleft", valueString, "topleft", -2, 4) + valueString.Background:SetPoint("bottomright", valueString, "bottomright", 2, -4) + end + + self.lineIndicatorValueFrame:Show() + self.lineIndicatorValueFrame:ClearAllPoints() + --self.lineIndicatorValueFrame:SetPoint("bottomleft", indicator, "bottomright", 2, 0) + + local leftValue = indicator.left + + indicator:SetScript("OnUpdate", function() + local newLeftValue = indicator:GetLeft() + local leftDiff = newLeftValue - leftValue --how much the indicator was moved + + local value = lineIndicator_GetValueForMoving(self, indicator, leftDiff) + leftValue = newLeftValue + indicator.left = newLeftValue + + --detailsFramework:DebugVisibility(self.lineIndicatorValueFrame) + self.lineIndicatorValueFrame:SetPoint("topleft", targetFrame, "topleft", newLeftValue + 2, -2) + + if (indicator.data.valueType == "TIME") then + self.lineIndicatorValueFrame.lineIndicatorValueFontString:SetText(detailsFramework:IntegerToTimer(value)) + + elseif (indicator.data.valueType == "PERCENT") then + self.lineIndicatorValueFrame.lineIndicatorValueFontString:SetText(format("%.2f%%", value * 100)) + + elseif (indicator.data.valueType == "PIXELS") then + self.lineIndicatorValueFrame.lineIndicatorValueFontString:SetText(value) + end + end) + end) + + indicator:SetScript("OnDragStop", function() + if (self.lineIndicatorValueFrame) then + self.lineIndicatorValueFrame:Hide() + end + + indicator:SetScript("OnUpdate", nil) + indicator:StopMovingOrSizing() + + --[=[ not over engineering this for now + --need to auto scroll the horizontal scroll frame if the indicator is moved + --get the amount of width that the horizontal scroll frame has scrolled + local horizontalScrolled = 0 + if (self.GetHorizontalScrolledWidth) then + horizontalScrolled = self:GetHorizontalScrolledWidth() or 0 + end + + --add the amount of width that the horizontal scroll frame has scrolled to the indicator left position + if (horizontalScrolled ~= 0) then + local diff = indicator.left + horizontalScrolled + local value = lineIndicator_GetValueForMoving(self, indicator, diff) + end + --]=] + + self:LineIndicatorRefresh() + end) + + indicator.Texture = texture + + return indicator + end, + + LineIndicatorGetLine = function(self) + assert(self.lineIndicators, "LineIndicatorGetLine(): LineIndicatorConstructor() not called.") + local thisIndicator = self.lineIndicators:Acquire() + return thisIndicator + end, + + LineIndicatorSetElapsedTime = function(self, totalTime) + self.lineIndicatorTotalTime = totalTime + end, + + LineIndicatorSetLinePosition = function(self, line, value, valueType) + local targetFrame = self:LineIndicatorGetTarget() + + if (valueType) then + if (valueType == "PERCENT") then + local effectiveWidth = targetFrame:GetWidth() - self.lineIndicatorXOffset + --effectiveWidth = effectiveWidth * self.lineIndicatorScale + local x = effectiveWidth * value + line:ClearAllPoints() + line:SetPoint("topleft", targetFrame, "topleft", self.lineIndicatorXOffset + x, 0) + line.xOffset = x + + elseif (valueType == "TIME") then + assert(self.lineIndicatorTotalTime > 0, "LineIndicatorSetElapsedTime(self, totalTime) must be called before SetLineIndicatorPosition() with valueType TIME.") + + local timePercent = value / self.lineIndicatorTotalTime + + local effectiveWidth = targetFrame:GetWidth() - self.lineIndicatorXOffset + --effectiveWidth = effectiveWidth * self.lineIndicatorScale + + local x = effectiveWidth * timePercent + line:ClearAllPoints() + line:SetPoint("left", targetFrame, "left", self.lineIndicatorXOffset + x, 0) + line:SetHeight(GetScreenHeight()) + line.xOffset = x + line.left = line:GetLeft() + + elseif (valueType == "PIXELS") then + --value = value * self.lineIndicatorScale + line:ClearAllPoints() + line:SetPoint("topleft", targetFrame, "topleft", self.lineIndicatorXOffset + value, 0) + line.xOffset = x + end + end + end, + + LineIndicatorRefresh = function(self) + --release all objects + self.lineIndicators:Reset() + --redraw all objects + for i = 1, #self.lineIndicatorData do + local data = self.lineIndicatorData[i] + if (not data.valueType) then + data.valueType = self.lineIndicatorValueType + end + + local line = self:LineIndicatorAddLine(data.value, data.valueType) + + line.index = i + line.data = data + + if (self.lineIndicatorLineHeight == -1) then + line:SetHeight(GetScreenHeight() * 2) + else + line:SetHeight(self.lineIndicatorLineHeight) + end + + line:SetWidth(data.width or self.lineIndicatorLineWidth) + line:SetAlpha(data.alpha or 1) + line.Texture:SetVertexColor(unpack(self.lineIndicatorColor)) + + line:SetScript("OnClick", data.onClick) + line:SetScript("OnEnter", data.onEnter) + line:SetScript("OnLeave", data.onLeave) + + if (self.lineIndicatorMouseEnabled) then + + end + end + end, + + LineIndicatorSetValueType = function(self, valueType) + assert(valueType == "PERCENT" or valueType == "TIME" or valueType == "PIXELS", "SetLineIndicatorValueType(valueType): valueType must be PERCENT, TIME or PIXELS.") + self.lineIndicatorValueType = valueType + end, + + LineIndicatorAddLine = function(self, value, valueType) + local line = self:LineIndicatorGetLine() + self:LineIndicatorSetLinePosition(line, value, valueType or self.lineIndicatorValueType) + line:Show() + return line + end, + + LineIndicatorRemoveData = function(self, dataId) + assert(type(dataId) == "number" or type(dataId) == "table", "LineIndicatorRemoveData(dataId): dataId must be the data index or a data table.") + + if (type(dataId) == "number") then + local index = dataId + table.remove(self.lineIndicatorData, index) + + elseif (type(dataId) == "table") then + local dataTable = dataId + for i = 1, #self.lineIndicatorData do + if (self.lineIndicatorData[i] == dataTable) then + table.remove(self.lineIndicatorData, i) + break + end + end + end + + self:LineIndicatorRefresh() + end, + + LineIndicatorAddData = function(self, data) + self.lineIndicatorData[#self.lineIndicatorData+1] = data + self:LineIndicatorRefresh() + end, + + LineIndicatorSetData = function(self, data) + self.lineIndicatorData = data + self:LineIndicatorRefresh() + end, + + LineIndicatorSetXOffset = function(self, xOffset) + self.lineIndicatorXOffset = xOffset + end, + + LineIndicatorSetScale = function(self, scale) + self.lineIndicatorScale = scale + end, + + LineIndicatorSetAllLinesHeight = function(self, height) + assert(type(height) == "number", "LineIndicatorSetAllLinesHeight(height): height must be a number.") + self.lineIndicatorLineHeight = height + self:LineIndicatorRefresh() + end, + + LineIndicatorSetAllLinesWidth = function(self, width) + assert(type(width) == "number", "LineIndicatorSetAllLinesWidth(width): width must be a number.") + self.lineIndicatorLineWidth = width + self:LineIndicatorRefresh() + end, + + LineIndicatorSetLineWidth = function(self, dataId, newWidth) + assert(type(dataId) == "number" or type(dataId) == "table", "LineIndicatorSetLineWidth(dataId): dataId must be the data index or a data table.") + + if (type(dataId) == "number") then + local index = dataId + local data = self.lineIndicatorData[index] + if (data) then + data.width = newWidth + end + + elseif (type(dataId) == "table") then + local dataTable = dataId + for i = 1, #self.lineIndicatorData do + if (self.lineIndicatorData[i] == dataTable) then + self.lineIndicatorData[i].width = newWidth + break + end + end + end + + self:LineIndicatorRefresh() + end, + + LineIndicatorSetAllLinesColor = function(self, color, g, b) + local r, g, b = detailsFramework:ParseColors(color, g, b) + self.lineIndicatorColor[1] = r + self.lineIndicatorColor[2] = g + self.lineIndicatorColor[3] = b + self:LineIndicatorRefresh() + end, + + LineIndicatorSetLineColor = function(self, dataId, color, g, b) + assert(type(dataId) == "number" or type(dataId) == "table", "LineIndicatorSetLineColor(dataId): dataId must be the data index or a data table.") + + local r, g, b = detailsFramework:ParseColors(color, g, b) + + if (type(dataId) == "number") then + local index = dataId + local data = self.lineIndicatorData[index] + if (data) then + data.color[1] = r + data.color[2] = g + data.color[3] = b + end + + elseif (type(dataId) == "table") then + local dataTable = dataId + for i = 1, #self.lineIndicatorData do + if (self.lineIndicatorData[i] == dataTable) then + self.lineIndicatorData[i].color[1] = r + self.lineIndicatorData[i].color[2] = g + self.lineIndicatorData[i].color[3] = b + break + end + end + end + + self:LineIndicatorRefresh() + end, + + LineIndicatorSetLineAlpha = function(self, dataId, alpha) + assert(type(dataId) == "number" or type(dataId) == "table", "LineIndicatorSetLineAlpha(dataId): dataId must be the data index or a data table.") + + if (type(dataId) == "number") then + local index = dataId + local data = self.lineIndicatorData[index] + if (data) then + data.alpha = alpha + end + + elseif (type(dataId) == "table") then + local dataTable = dataId + for i = 1, #self.lineIndicatorData do + if (self.lineIndicatorData[i] == dataTable) then + self.lineIndicatorData[i].alpha = alpha + break + end + end + end + + self:LineIndicatorRefresh() + end, +} \ No newline at end of file diff --git a/Libs/DF/load.xml b/Libs/DF/load.xml index accfddc8b..9f4fd248d 100644 --- a/Libs/DF/load.xml +++ b/Libs/DF/load.xml @@ -34,8 +34,11 @@