From 692423182ebb1164dc89673572ffd1901d9eb9ba Mon Sep 17 00:00:00 2001 From: Tercio Jose Date: Thu, 14 Mar 2024 14:10:07 -0300 Subject: [PATCH] Framework Update --- libs/DF/buildmenu.lua | 5 +- libs/DF/button.lua | 109 ++-- libs/DF/cooltip.lua | 115 +++- libs/DF/definitions.lua | 210 +++++- libs/DF/dropdown.lua | 56 +- libs/DF/frames.lua | 80 --- libs/DF/fw.lua | 1115 +++++++++++++++++++++++--------- libs/DF/icongeneric.lua | 489 ++++++++++---- libs/DF/label.lua | 35 +- libs/DF/loadconditions.lua | 2 +- libs/DF/math.lua | 27 + libs/DF/normal_bar.lua | 2 +- libs/DF/panel.lua | 37 +- libs/DF/picture.lua | 392 ++++++++++- libs/DF/rounded_panel.lua | 18 +- libs/DF/scrollbox.lua | 153 ++++- libs/DF/slider.lua | 130 +++- libs/DF/split_bar.lua | 2 +- libs/DF/textentry.lua | 49 +- libs/DF/timebar.lua | 2 +- media/track_minimaps/66710.tga | Bin 0 -> 1048620 bytes racing_helper.lua | 330 +++++++++- 22 files changed, 2660 insertions(+), 698 deletions(-) create mode 100644 media/track_minimaps/66710.tga diff --git a/libs/DF/buildmenu.lua b/libs/DF/buildmenu.lua index e162ed36..00aa746c 100644 --- a/libs/DF/buildmenu.lua +++ b/libs/DF/buildmenu.lua @@ -32,6 +32,7 @@ local _ ---@field desc string ---@field descPhraseId string ---@field hooks table +---@field include_default boolean ---@class df_menu_toggle : df_menu_table ---@field set function @@ -962,7 +963,7 @@ function detailsFramework:BuildMenuVolatile(parent, menuOptions, xOffset, yOffse do if (widgetTable.type == "selectfont") then - local func = detailsFramework:CreateFontListGenerator(widgetTable.set) + local func = detailsFramework:CreateFontListGenerator(widgetTable.set, widgetTable.include_default) dropdown:SetFunction(func) elseif (widgetTable.type == "selectcolor") then @@ -1202,7 +1203,7 @@ function detailsFramework:BuildMenu(parent, menuOptions, xOffset, yOffset, heigh local dropdown do if (widgetTable.type == "selectfont") then - dropdown = detailsFramework:CreateFontDropDown(parent, widgetTable.set, widgetTable.get(), widgetWidth or 140, widgetHeight or defaultHeight, nil, "$parentWidget" .. index, dropdownTemplate) + dropdown = detailsFramework:CreateFontDropDown(parent, widgetTable.set, widgetTable.get(), widgetWidth or 140, widgetHeight or defaultHeight, nil, "$parentWidget" .. index, dropdownTemplate, widgetTable.include_default) elseif (widgetTable.type == "selectcolor") then dropdown = detailsFramework:CreateColorDropDown(parent, widgetTable.set, widgetTable.get(), widgetWidth or 140, widgetHeight or defaultHeight, nil, "$parentWidget" .. index, dropdownTemplate) diff --git a/libs/DF/button.lua b/libs/DF/button.lua index 4bea4cfd..c5c1e4ac 100644 --- a/libs/DF/button.lua +++ b/libs/DF/button.lua @@ -381,6 +381,8 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) end end + local noColor = {1, 1, 1, 1} + ---add an icon to the left of the button text ---short method truncates the text: false = do nothing, nil = increate the button width, 1 = decrease the font size, 2 = truncate the text ---@param texture any @@ -403,6 +405,16 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) self.widget.text:SetPoint("left", self.icon, "right", textDistance or 2, 0 + (textHeight or 0)) end + overlay = overlay or noColor + local red, green, blue, alpha = detailsFramework:ParseColors(overlay or noColor) + + local left, right, top, bottom = texcoord and texcoord[1], texcoord and texcoord[2], texcoord and texcoord[3], texcoord and texcoord[4] + texture, width, height, left, right, top, bottom, red, green, blue, alpha = detailsFramework:ParseTexture(texture, width, height, left, right, top, bottom, red, green, blue, alpha) + + if (red == nil) then + red, green, blue, alpha = 1, 1, 1, 1 + end + if (type(texture) == "string") then local isAtlas = C_Texture.GetAtlasInfo(texture) if (isAtlas) then @@ -414,33 +426,17 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) else self.icon:SetTexture(texture) end - - elseif (type(texture) == "table") then - local r, g, b, a = detailsFramework:ParseColors(texture) - self.icon:SetColorTexture(r, g, b, a) else self.icon:SetTexture(texture) end self.icon:SetSize(width or self.height * 0.8, height or self.height * 0.8) + self.icon:SetDrawLayer(layout or "artwork") - if (texcoord) then - self.icon:SetTexCoord(unpack(texcoord)) - else - self.icon:SetTexCoord(0, 1, 0, 1) - end + self.icon:SetTexCoord(left, right, top, bottom) - if (overlay) then - if (type(overlay) == "string") then - local r, g, b, a = detailsFramework:ParseColors(overlay) - self.icon:SetVertexColor(r, g, b, a) - else - self.icon:SetVertexColor(unpack(overlay)) - end - else - self.icon:SetVertexColor(1, 1, 1, 1) - end + self.icon:SetVertexColor(red, green, blue, alpha) local buttonWidth = self.button:GetWidth() local iconWidth = self.icon:GetWidth() @@ -481,12 +477,16 @@ 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 ---disable the button making it unclickable and grayed out ---@return unknown function ButtonMetaFunctions:Disable() + if (self.color_texture) then + self.color_texture:SetVertexColor(0.14, 0.14, 0.14) + end return self.button:Disable() end @@ -733,11 +733,9 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) ---receives a table where the keys are settings and the values are the values to set ---this is the list of keys the table support: ---width, height, icon|table, textcolor, textsize, textfont, textalign, backdrop, backdropcolor, backdropbordercolor, onentercolor, onleavecolor, onenterbordercolor, onleavebordercolor ----@param template table +---@param template table|string function ButtonMetaFunctions:SetTemplate(template) - if (type(template) == "string") then - template = detailsFramework:GetTemplate("button", template) - end + template = detailsFramework:ParseTemplate(self.type, template) if (not template) then detailsFramework:Error("template not found") @@ -808,6 +806,25 @@ function ButtonMetaFunctions:SetTemplate(template) if (template.textalign) then self.textalign = template.textalign end + + if (template.rounded_corner) then + self:SetBackdrop(nil) + detailsFramework:AddRoundedCornersToFrame(self.widget or self, template.rounded_corner) + + --check if this is a color picker button + if (self.__iscolorpicker) then + self.color_texture:SetTexture([[Interface\CHARACTERFRAME\TempPortraitAlphaMaskSmall]], "CLAMP", "CLAMP", "TRILINEAR") + self.color_texture:SetDrawLayer("overlay", 7) + self.color_texture:SetPoint("topleft", self.widget, "topleft", 2, -2) + self.color_texture:SetPoint("bottomright", self.widget, "bottomright", -2, 2) + + self.background_texture:SetDrawLayer("overlay", 6) + self.background_texture:SetPoint("topleft", self.color_texture, "topleft", 2, -2) + self.background_texture:SetPoint("bottomright", self.color_texture, "bottomright", -2, 2) + + self.widget.texture_disabled:SetTexture([[Interface\CHARACTERFRAME\TempPortraitAlphaMaskSmall]], "CLAMP", "CLAMP", "TRILINEAR") + end + end end ------------------------------------------------------------------------------------------------------------ @@ -840,7 +857,7 @@ end self:SetScript("OnEnable", onEnableFunc) end - ---@class df_button : button, df_scripthookmixin + ---@class df_button : button, df_scripthookmixin, df_widgets ---@field widget button ---@field tooltip string ---@field shown boolean @@ -857,7 +874,7 @@ end ---@field textfont string ---@field textsize number ---@field icon texture created after calling SetIcon() - ---@field SetTemplate fun(self: df_button, template: table) set the button visual by a template + ---@field SetTemplate fun(self: df_button, template: table|string) set the button visual by a template ---@field RightClick fun(self: df_button) right click the button executing its right click function ---@field Exec fun(self: df_button) execute the button function for the left button ---@field Disable fun(self: df_button) disable the button @@ -873,8 +890,8 @@ end ---@field SetClickFunction fun(self: df_button, func: function, param1: any, param2: any, clickType: "left"|"right"|nil) ---create a Details Framework button - ---@param parent table - ---@param func function + ---@param parent frame + ---@param callback function ---@param width number ---@param height number ---@param text any @@ -887,8 +904,8 @@ end ---@param buttonTemplate table|nil ---@param textTemplate table|nil ---@return df_button - function detailsFramework:CreateButton(parent, func, width, height, text, param1, param2, texture, member, name, shortMethod, buttonTemplate, textTemplate) - return detailsFramework:NewButton(parent, parent, name, member, width, height, func, param1, param2, texture, text, shortMethod, buttonTemplate, textTemplate) + function detailsFramework:CreateButton(parent, callback, width, height, text, param1, param2, texture, member, name, shortMethod, buttonTemplate, textTemplate) + return detailsFramework:NewButton(parent, parent, name, member, width, height, callback, param1, param2, texture, text, shortMethod, buttonTemplate, textTemplate) end ---@return df_button @@ -1064,6 +1081,15 @@ end return self.color_texture:GetVertexColor() end + ---@class df_colorpickbutton : df_button + ---@field color_callback function + ---@field Cancel function + ---@field SetColor function + ---@field GetColor function + ---@field __iscolorpicker boolean + ---@field color_texture texture + ---@field background_texture texture + ---create a button which opens a color picker when clicked ---@param parent table ---@param name string|nil @@ -1077,33 +1103,38 @@ end end function detailsFramework:NewColorPickButton(parent, name, member, callback, alpha, buttonTemplate) - --button - local colorPickButton = detailsFramework:NewButton(parent, _, name, member, 16, 16, pickcolor, alpha, "param2", nil, nil, nil, buttonTemplate) + local colorPickButton = detailsFramework:NewButton(parent, _, name, member, 16, 16, pickcolor, alpha, "param2") + ---@cast colorPickButton df_colorpickbutton + colorPickButton.color_callback = callback colorPickButton.Cancel = colorpickCancel colorPickButton.SetColor = setColorPickColor colorPickButton.GetColor = getColorPickColor + colorPickButton.__iscolorpicker = true colorPickButton.HookList.OnColorChanged = {} - if (not buttonTemplate) then - colorPickButton:SetTemplate(detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")) - end - --background showing a grid to indicate the transparency - local background = colorPickButton:CreateTexture(nil, "background", nil, 2) + local background = colorPickButton:CreateTexture("$parentBackgroupTransparency", "background", nil, 2) background:SetPoint("topleft", colorPickButton.widget, "topleft", 0, 0) background:SetPoint("bottomright", colorPickButton.widget, "bottomright", 0, 0) - background:SetTexture([[Interface\ITEMSOCKETINGFRAME\UI-EMPTYSOCKET]]) - background:SetTexCoord(3/16, 13/16, 3/16, 13/16) + background:SetAtlas("AnimCreate_Icon_Texture") background:SetAlpha(0.3) + colorPickButton.background_texture = background --texture which shows the texture color - local colorTexture = detailsFramework:NewImage(colorPickButton, nil, 16, 16, nil, nil, "color_texture", "$parentTex") + local colorTexture = colorPickButton:CreateTexture("$parentTex", "overlay") colorTexture:SetColorTexture(1, 1, 1) colorTexture:SetPoint("topleft", colorPickButton.widget, "topleft", 0, 0) colorTexture:SetPoint("bottomright", colorPickButton.widget, "bottomright", 0, 0) colorTexture:SetDrawLayer("background", 3) + colorPickButton.color_texture = colorTexture + + if (not buttonTemplate) then + colorPickButton:SetTemplate(detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")) + else + colorPickButton:SetTemplate(buttonTemplate) + end return colorPickButton end diff --git a/libs/DF/cooltip.lua b/libs/DF/cooltip.lua index 81ebdec6..94b8e32b 100644 --- a/libs/DF/cooltip.lua +++ b/libs/DF/cooltip.lua @@ -4,6 +4,8 @@ if (not DF or not DetailsFrameworkCanLoad) then return end +local detailsFramework = DF + local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0") local _ @@ -15,7 +17,7 @@ local max = math.max --api locals local PixelUtil = PixelUtil or DFPixelUtil -local version = 20 +local version = 24 local CONST_MENU_TYPE_MAINMENU = "main" local CONST_MENU_TYPE_SUBMENU = "sub" @@ -34,6 +36,7 @@ function DF:CreateCoolTip() tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0}} local defaultBackdropColor = {0.1215, 0.1176, 0.1294, 0.8000} local defaultBackdropBorderColor = {0.05, 0.05, 0.05, 1} + local defaultTexCoord = {0, 1, 0, 1} --initialize local gameCooltip = { @@ -103,7 +106,7 @@ function DF:CreateCoolTip() --options table gameCooltip.OptionsList = { - ["RightTextMargin"] = true, + ["RightTextMargin"] = true, --offset between the right text to the right icon, default: -3 ["IconSize"] = true, ["HeightAnchorMod"] = true, ["WidthAnchorMod"] = true, @@ -119,10 +122,10 @@ function DF:CreateCoolTip() ["TextHeightMod"] = true, ["ButtonHeightMod"] = true, ["ButtonHeightModSub"] = true, - ["YSpacingMod"] = true, + ["YSpacingMod"] = true, --space between each line, does not work with 'IgnoreButtonAutoHeight' and 'AlignAsBlizzTooltip' ["YSpacingModSub"] = true, - ["ButtonsYMod"] = true, - ["ButtonsYModSub"] = true, + ["ButtonsYMod"] = true, --amount of space to leave between the top border and the first line of the tooltip, default: 0 + ["ButtonsYModSub"] = true, --amount of space to leave between the top border and the first line of the tooltip, default: 0 ["IconHeightMod"] = true, ["StatusBarHeightMod"] = true, ["StatusBarTexture"] = true, @@ -141,8 +144,8 @@ function DF:CreateCoolTip() ["RelativeAnchor"] = true, ["NoLastSelectedBar"] = true, ["SubMenuIsTooltip"] = true, - ["LeftBorderSize"] = true, - ["RightBorderSize"] = true, + ["LeftBorderSize"] = true, --offset between the left border and the left icon, default: 10 + offset + ["RightBorderSize"] = true, --offset between the right border and the right icon, default: -10 + offset ["HeighMod"] = true, ["HeighModSub"] = true, ["IconBlendMode"] = true, @@ -189,7 +192,7 @@ function DF:CreateCoolTip() --move each line in the Y axis (vertical offsett) ["LineYOffset"] = "ButtonsYMod", - ["VerticalOffset"] = "ButtonsYMod", + ["VerticalOffset"] = "ButtonsYMod", --amount of space to leave between the top border and the first line of the tooltip, default: 0 ["LineYOffsetSub"] = "ButtonsYModSub", ["VerticalOffsetSub"] = "ButtonsYModSub", } @@ -229,7 +232,7 @@ function DF:CreateCoolTip() gameCooltip.RoundedFramePreset = { color = {.075, .075, .075, 1}, - border_color = {.2, .2, .2, 1}, + border_color = {.3, .3, .3, 1}, roundness = 8, } @@ -375,6 +378,9 @@ function DF:CreateCoolTip() frame1.frameBackgroundTexture:Hide() frame2.frameBackgroundTexture:Hide() + + frame1.gradientTexture:Hide() + frame2.gradientTexture:Hide() end function GameCooltip:HideRoundedCorner() @@ -387,6 +393,9 @@ function DF:CreateCoolTip() frame1.frameBackgroundTexture:Show() frame2.frameBackgroundTexture:Show() + + frame1.gradientTexture:Show() + frame2.gradientTexture:Show() end gameCooltip.frame1 = frame1 @@ -610,10 +619,18 @@ function DF:CreateCoolTip() statusbar.leftIcon:SetSize(16, 16) statusbar.leftIcon:SetPoint("LEFT", statusbar, "LEFT", 0, 0) + statusbar.leftIconMask = statusbar:CreateMaskTexture("$parent_LeftIconMask", "artwork") + statusbar.leftIconMask:SetAllPoints(statusbar.leftIcon) + statusbar.leftIcon:AddMaskTexture(statusbar.leftIconMask) + statusbar.rightIcon = statusbar:CreateTexture("$parent_RightIcon", "OVERLAY") statusbar.rightIcon:SetSize(16, 16) statusbar.rightIcon:SetPoint("RIGHT", statusbar, "RIGHT", 0, 0) + statusbar.rightIconMask = statusbar:CreateMaskTexture("$parent_RightIconMask", "artwork") + statusbar.rightIconMask:SetAllPoints(statusbar.rightIcon) + statusbar.rightIcon:AddMaskTexture(statusbar.rightIconMask) + statusbar.spark2 = statusbar:CreateTexture("$parent_Spark2", "OVERLAY") statusbar.spark2:SetSize(32, 32) statusbar.spark2:SetPoint("LEFT", statusbar, "RIGHT", -17, -1) @@ -656,6 +673,8 @@ function DF:CreateCoolTip() self:RegisterForClicks("LeftButtonDown") self.leftIcon = self.statusbar.leftIcon self.rightIcon = self.statusbar.rightIcon + self.leftIconMask = self.statusbar.leftIconMask + self.rightIconMask = self.statusbar.rightIconMask self.texture = self.statusbar.texture self.spark = self.statusbar.spark self.spark2 = self.statusbar.spark2 @@ -934,7 +953,7 @@ function DF:CreateCoolTip() if (gameCooltip.FunctionsTableMain[self.index]) then local parameterTable = gameCooltip.ParametersTableMain[self.index] local func = gameCooltip.FunctionsTableMain[self.index] - local okay, errortext = pcall(func, gameCooltip.Host, gameCooltip.FixedValue, parameterTable[1], parameterTable[2], parameterTable[3], button) + local okay, errortext = xpcall(func, geterrorhandler(), gameCooltip.Host, gameCooltip.FixedValue, parameterTable[1], parameterTable[2], parameterTable[3], button) if (not okay) then print("Cooltip OnClick Error:", errortext) end @@ -948,7 +967,7 @@ function DF:CreateCoolTip() if (gameCooltip.FunctionsTableSub[self.mainIndex] and gameCooltip.FunctionsTableSub[self.mainIndex][self.index]) then local parameterTable = gameCooltip.ParametersTableSub[self.mainIndex][self.index] local func = gameCooltip.FunctionsTableSub[self.mainIndex][self.index] - local okay, errortext = pcall(func, gameCooltip.Host, gameCooltip.FixedValue, parameterTable[1], parameterTable[2], parameterTable[3], button) + local okay, errortext = xpcall(func, geterrorhandler(), gameCooltip.Host, gameCooltip.FixedValue, parameterTable[1], parameterTable[2], parameterTable[3], button) if (not okay) then print("Cooltip OnClick Error:", errortext) end @@ -1180,6 +1199,16 @@ function DF:CreateCoolTip() textureObject:SetHeight(leftIconSettings[3]) textureObject:SetTexCoord(leftIconSettings[4], leftIconSettings[5], leftIconSettings[6], leftIconSettings[7]) + if (leftIconSettings[10]) then + menuButton.leftIconMask:SetTexture(leftIconSettings[10]) + else + if (DF.IsDragonflightAndBeyond()) then + menuButton.leftIconMask:SetTexture([[Interface\COMMON\common-iconmask]]) + else + menuButton.leftIconMask:SetTexture([[Interface\CHATFRAME\chatframebackground]]) + end + end + local colorRed, colorGreen, colorBlue, colorAlpha = DF:ParseColors(leftIconSettings[8]) textureObject:SetVertexColor(colorRed, colorGreen, colorBlue, colorAlpha) @@ -1237,6 +1266,12 @@ function DF:CreateCoolTip() menuButton.rightIcon:SetHeight(rightIconSettings[3]) menuButton.rightIcon:SetTexCoord(rightIconSettings[4], rightIconSettings[5], rightIconSettings[6], rightIconSettings[7]) + if (rightIconSettings[10]) then + menuButton.rightIconMask:SetTexture(rightIconSettings[10]) + else + menuButton.rightIconMask:SetTexture([[Interface\COMMON\common-iconmask]]) + end + local colorRed, colorGreen, colorBlue, colorAlpha = DF:ParseColors(rightIconSettings[8]) menuButton.rightIcon:SetVertexColor(colorRed, colorGreen, colorBlue, colorAlpha) @@ -1496,6 +1531,9 @@ function DF:CreateCoolTip() wallpaper:SetDesaturated(true) else wallpaper:SetDesaturated(false) + if (wallpaperTable[8]) then + wallpaper:SetDesaturation(wallpaperTable[8]) + end end wallpaper:Show() @@ -3001,7 +3039,16 @@ function DF:CreateCoolTip() frame1.frameWallpaper:Hide() frame2.frameWallpaper:Hide() - function gameCooltip:SetWallpaper(menuType, texture, texcoord, color, desaturate) + + ---set an image as wallpaper for the cooltip frame + ---@param menuType any + ---@param texture any + ---@param texcoord table + ---@param color any + ---@param bDesaturated boolean? + ---@param desaturation number? + ---@return nil + function gameCooltip:SetWallpaper(menuType, texture, texcoord, color, bDesaturated, desaturation) if (gameCooltip.Indexes == 0) then return gameCooltip:PrintDebug("SetWallpaper() requires an already added line (Cooltip:AddLine()).") end @@ -3024,20 +3071,18 @@ function DF:CreateCoolTip() wallpaperTable = subMenuContainerWallpapers end - wallpaperTable[1] = texture - if (texcoord) then - wallpaperTable[2] = texcoord[1] - wallpaperTable[3] = texcoord[2] - wallpaperTable[4] = texcoord[3] - wallpaperTable[5] = texcoord[4] - else - wallpaperTable[2] = 0 - wallpaperTable[3] = 1 - wallpaperTable[4] = 0 - wallpaperTable[5] = 1 - end - wallpaperTable[6] = color - wallpaperTable[7] = desaturate + texcoord = texcoord or defaultTexCoord + + --parse the texure + local iconTexture, iconWidth, iconHeight, leftCoord, rightCoord, topCoord, bottomCoord, red, green, blue, alpha = detailsFramework:ParseTexture(texture, 1, 1, texcoord[1], texcoord[2], texcoord[3], texcoord[4], color) + wallpaperTable[1] = iconTexture + wallpaperTable[2] = leftCoord + wallpaperTable[3] = rightCoord + wallpaperTable[4] = topCoord + wallpaperTable[5] = bottomCoord + wallpaperTable[6] = {red, green, blue, alpha} + wallpaperTable[7] = bDesaturated or false + wallpaperTable[8] = desaturation end function gameCooltip:SetBannerText(menuType, index, text, anchor, color, fontSize, fontFace, fontFlag) @@ -3173,14 +3218,24 @@ function DF:CreateCoolTip() return gameCooltip:AddIcon(iconTexture, menuType, side, iconWidth, iconHeight, leftCoord, rightCoord, topCoord, bottomCoord, overlayColor, point, desaturated) end - function gameCooltip:AddIcon(iconTexture, menuType, side, iconWidth, iconHeight, leftCoord, rightCoord, topCoord, bottomCoord, overlayColor, point, desaturated) + function gameCooltip:AddIcon(iconTexture, menuType, side, iconWidth, iconHeight, leftCoord, rightCoord, topCoord, bottomCoord, overlayColor, point, desaturated, mask) --need a previous line if (gameCooltip.Indexes == 0) then return gameCooltip:PrintDebug("AddIcon() requires an already added line (Cooltip:AddLine()).") end + --check data integrity - if ((type(iconTexture) ~= "string" and type(iconTexture) ~= "number") and (type(iconTexture) ~= "table" or not iconTexture.GetObjectType or iconTexture:GetObjectType() ~= "Texture")) then - return gameCooltip:PrintDebug("AddIcon() invalid parameters.") + local bCheckTextureObject = true + if (not detailsFramework:IsTexture(iconTexture, bCheckTextureObject)) then + return gameCooltip:PrintDebug("AddIcon() invalid texture.") + end + + --parse the texure + local red, green, blue, alpha + iconTexture, iconWidth, iconHeight, leftCoord, rightCoord, topCoord, bottomCoord, red, green, blue, alpha = detailsFramework:ParseTexture(iconTexture, iconWidth, iconHeight, leftCoord, rightCoord, topCoord, bottomCoord, overlayColor) + + if (not overlayColor and red) then + overlayColor = {red, green, blue, alpha} end side = side or 1 @@ -3225,6 +3280,7 @@ function DF:CreateCoolTip() gameCooltip.TopIconTableSub[gameCooltip.Indexes][7] = bottomCoord or 1 gameCooltip.TopIconTableSub[gameCooltip.Indexes][8] = overlayColor or defaultWhiteColor gameCooltip.TopIconTableSub[gameCooltip.Indexes][9] = desaturated + gameCooltip.TopIconTableSub[gameCooltip.Indexes][10] = mask return end @@ -3257,6 +3313,7 @@ function DF:CreateCoolTip() iconTable[7] = bottomCoord or 1 --default 1 iconTable[8] = overlayColor or defaultWhiteColor --default 1, 1, 1 iconTable[9] = desaturated + iconTable[10] = mask return true end diff --git a/libs/DF/definitions.lua b/libs/DF/definitions.lua index b9184df8..2f413928 100644 --- a/libs/DF/definitions.lua +++ b/libs/DF/definitions.lua @@ -11,7 +11,8 @@ ---@field removeduplicate fun(tbl1:table, tbl2:table) remove the keys from table1 which also exists in table2 with the same value ---@field getfrompath fun(tbl:table, path:string, subOffset:number?) : any get a value from a table using a path, e.g. getfrompath(tbl, "a.b.c") is the same as tbl.a.b.c; if subOffset is passed, return the subOffset'th value of the path ---@field setfrompath fun(tbl:table, path:string, value:any) : boolean set the value of a table using a path, e.g. setfrompath(tbl, "a.b.c", 10) is the same as tbl.a.b.c = 10 ----@field dump fun(tbl:table) : string dump a table to a string +---@field dump fun(tbl:table, resultString:string, deep:number) : string dump a table to a string +---@field findsubtable fun(tbl:table, index:number, value:any) : integer|nil find the value passed inside a sub table, return the index of the main table where the sub table with the value found is located ---@class df_language : table ---@field Register fun(addonId:any, languageId:string, gameLanguageOnly:boolean?) : table @@ -36,13 +37,88 @@ ---@field RegisterTableKeyWithLocTable fun(table:table, key:any, locTable:table, silence:boolean?) ---@field RegisterObjectWithLocTable fun(object:uiobject, locTable:table, silence:boolean?) ----@alias templatetype +---@class df_anttable : table +---@field Throttle number +---@field AmountParts number +---@field TexturePartsWidth number +---@field TexturePartsHeight number +---@field TextureWidth number +---@field TextureHeight number +---@field BlendMode string? +---@field Color any? +---@field Texture any + +---df version of an atlasinfo from the game API, it include color and desaturation information +---a df atlas can be created using DetailsFramework:CreateAtlas() and then used with DetailsFramework:SetAtlas() +---@class df_atlasinfo : atlasinfo +---@field vertexRed number? +---@field vertexGreen number? +---@field vertexBlue number? +---@field vertexAlpha number? +---@field colorName string? +---@field nativeWidth number? +---@field nativeHeight number? +---@field desaturated boolean? +---@field desaturation number? +---@field atlas string? + +---@alias df_templatename string + +---a template is a table with keys and values that mandate how a widget should look like +---@class df_template : table +---@field width any +---@field height any +---@field backdrop any +---@field backdropcolor any +---@field backdropbordercolor any +---@field onentercolor any +---@field onleavecolor any +---@field onenterbordercolor any +---@field onleavebordercolor any +---@field icon any +---@field size any +---@field textsize any +---@field font any +---@field textfont any +---@field color any +---@field textcolor any +---@field textalign any +---@field rounded_corner any +---@field thumbtexture any +---@field slider_left any +---@field slider_right any +---@field slider_middle any +---@field thumbwidth any +---@field thumbheight any +---@field thumbcolor any +---@field amount_color any +---@field amount_outline any +---@field amount_size any +---@field enabled_backdropcolor any +---@field disabled_backdropcolor any +---@field is_checkbox any +---@field checked_texture any +---@field checked_xoffset any +---@field checked_yoffset any +---@field checked_size_percent any +---@field checked_color any + + + +---@class df_widgets : table +---@field type string +---@field dframework boolean +---@field container frame +---@field widget frame + +---@alias templatecategory ---| "font" ---| "dropdown" ---| "button" ---| "switch" ---| "slider" + ---@class detailsframework ---@field dversion number ---@field internalFunctions table @@ -56,12 +132,48 @@ ---@field KeybindMixin df_keybindmixin ---@field ScriptHookMixin df_scripthookmixin ---@field EditorMixin df_editormixin +---@field ScrollBoxFunctions df_scrollboxmixin ---@field ClassCache {ID:number, Name:string, FileString:string, Texture:string, TexCoord:number[]}[] only available after calling GetClassList() ---@field Math df_math ---@field FontOutlineFlags table ---@field table df_table_functions ---@field AnchorPoints string[] +---@field alias_text_colors table ---@field ClassFileNameToIndex table engClass -> classIndex +---@field ClientLanguage string +---@field dropdown_templates table +---@field switch_templates table +---@field button_templates table +---@field slider_templates table +---@field font_templates table +---@field FrameWorkVersion string the version of the framework +---@field LabelNameCounter number when no name is given, a string plus an incremental number is used instead +---@field PictureNameCounter number when no name is given, a string plus an incremental number is used instead +---@field BarNameCounter number when no name is given, a string plus an incremental number is used instead +---@field DropDownCounter number when no name is given, a string plus an incremental number is used instead +---@field PanelCounter number when no name is given, a string plus an incremental number is used instead +---@field SimplePanelCounter number when no name is given, a string plus an incremental number is used instead +---@field ButtonCounter number when no name is given, a string plus an incremental number is used instead +---@field SliderCounter number when no name is given, a string plus an incremental number is used instead +---@field SwitchCounter number when no name is given, a string plus an incremental number is used instead +---@field SplitBarCounter number when no name is given, a string plus an incremental number is used instead +---@field TalentExporter table +---@field FormatNumber fun(number:number) : string abbreviate a number, e.g. 1000 -> 1k 1000 -> 1천, depending on the client language +---@field UnitGroupRolesAssigned fun(unitId: unit, bUseSupport:boolean?, specId: specializationid?) : string there's no self here +---@field IsDragonflight fun():boolean +---@field IsDragonflightAndBeyond fun():boolean +---@field IsTimewalkWoW fun():boolean +---@field IsClassicWow fun():boolean +---@field IsTBCWow fun():boolean +---@field IsWotLKWow fun():boolean +---@field IsCataWow fun():boolean +---@field IsPandaWow fun():boolean +---@field IsWarlordsWow fun():boolean +---@field IsLegionWow fun():boolean +---@field IsBFAWow fun():boolean +---@field IsShadowlandsWow fun():boolean +---@field IsDragonflightWow fun():boolean +---@field IsWarWow fun():boolean ---@field LoadSpellCache fun(self:table, hashMap:table, indexTable:table, allSpellsSameName:table) : hashMap:table, indexTable:table, allSpellsSameName:table load all spells in the game and add them into the passed tables ---@field UnloadSpellCache fun(self:table) wipe the table contents filled with LoadSpellCache() ---@field GetCurrentClassName fun(self:table) : string return the name of the class the player is playing @@ -70,7 +182,9 @@ ---@field GetCurrentSpec fun(self:table):number? ---@field GetCurrentSpecId fun(self:table):number? return the specId of the current spec, retuns nil if the expansion the player is playing does not support specs ---@field GetClassSpecIds fun(self:table, engClass:string):number[] +---@field GetClassSpecIDs fun(self:table, engClass:string):number[] ---@field IsValidSpecId fun(self:table, specId:number):boolean check if the passed specId is valid for the player class, also return false for tutorial specs +---@field GetDragonlightTalentString fun(self:table):string return the talent config string ---@field GetClassList fun(self:table):{ID:number, Name:string, FileString:string, Texture:string, TexCoord:number[]}[] ---@field DebugVisibility fun(self:table, object:uiobject) print the reason why the frame isn't shown in the screen ---@field Dispatch fun(self:table, callback:function, ...) : any dispatch a function call using xpcall, print to chat if the function passed is invalid @@ -93,9 +207,10 @@ ---@field GetFontSize fun(self:table, fontstring:fontstring) : number return the font size of the fontstring ---@field SetFontColor fun(self:table, fontstring:fontstring, red:any, green:number?, blue:number?, alpha:number?) ---@field SetFontFace fun(self:table, fontstring:fontstring, font:string) +---@field SetFontDefault fun(self:table, fontstring:fontstring) ---@field GetFontFace fun(self:table, fontstring:fontstring) : string return the font face of the fontstring ---@field SetFontShadow fun(self:table, fontstring:fontstring, red:any, green:number?, blue:number?, alpha:number?, offsetX:number?, offsetY:number?) ----@field SetFontOutline fun(self:table, fontstring:fontstring, outline:fontflags) +---@field SetFontOutline fun(self:table, fontstring:fontstring, outline:outline) ---@field RemoveRealmName fun(self:table, name:string) : string, number remove the realm name from the player name, must be in the format of "name-realm" ---@field RemoveOwnerName fun(self:table, name:string) : string, number removes the owner name from a name string, the owner name must be between < and > ---@field CleanUpName fun(self:table, name:string) : string removes the realm name and owner name from a name string @@ -103,23 +218,25 @@ ---@field GroupIterator fun(self:table, callback:function, ...) iterate over the group, calling the callback function for each group member ---@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?) 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 AddTextureToText fun(self:table, text:string, textureInfo:table, bAddSpace:boolean?, bAddAfterText:any) : string textureInfo is a table with .texture .width .height .coords{left, right, top, bottom} +---@field CreateTextureInfo fun(self:table, texture:atlasname|texturepath|textureid, width:number?, height:number?, left:number?, right:number?, top:number?, bottom:number?, imageWidthnumber?, imageHeightnumber?) : table deprecated, use: DetailsFramework:CreateAtlas() ---@field ApplyStandardBackdrop fun(self:table, frame:frame, bUseSolidColor:boolean?, alphaScale:number?) ----@field CreateLabel fun(self:table, parent:frame, text:string, size:number?, color:any?, font:string?, member:string?, name:string?, layer:drawlayer?) : df_label +---@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:string, size:any?, color:any?, font:string?, member:string?, name:string?, layer:drawlayer?) : df_label ---@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 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 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 CreateTextEntry fun(self:table, parent:frame, textChangedCallback:function, width:number, height:number, member:string?, name:string?, labelText:string?, textentryTemplate:table?, labelTemplate:table?) : df_textentry ---@field ReskinSlider fun(self:table, slider:frame) ---@field GetAvailableSpells fun(self:table) : table ----@field NewColor fun(self:table, colorName:string, red:number, green:number, blue:number, alpha:number) +---@field NewColor fun(self:table, colorName:string, red:number, green:number, blue:number, alpha:number?) : table ---@field CreateKeybindFrame fun(self:table, parent:frame, name:string?, options:table?, setKeybindCallback:function?, keybindData:table?) : df_keybindframe ---@field CreateStatusBar fun(self:table, parent:frame, options:table?) : frame ----@field GetTemplate fun(self:table, templateType:templatetype, templateName:string) : table +---@field GetTemplate fun(self:table, templatecategory:templatecategory, templateName:string) : table ---@field UpdateLoadConditionsTable fun(self:table, loadConditionsTable:table) ---@field IconPick fun(self:table, callback:function, bCloseWhenSelect:boolean?, param1:any?, param2:any?) ---@field OpenLoadConditionsPanel fun(self:table, optionsTable:table, callback:function, frameOptions:table?) @@ -142,9 +259,80 @@ ---@field GetColorHue fun(self:table, r:number, g:number, b:number) : number return the hue of a color from red to blue to green to yellow and back to red ---@field IsHtmlColor fun(self:table, colorName:any) : unknown return true if DF.alias_text_colors has the colorName as a key ---@field CreateColorTable fun(self:table, r:number, g:number, b:number, a:number) : table return a table with {r, g, b, a} ----@field FormatColor fun(self:table, newFormat:string, r:number|string, 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 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 +---@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_button +---@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 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 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 +---@field NewImage fun(self:table, parent:frame, texture:atlasname|texturepath|textureid|df_gradienttable|nil, width:number?, height:number?, layer:drawlayer?, texCoord:table?, member:string?, name:string?) : df_image +---@field CreateTexture fun(self:table, parent:frame, texture:atlasname|texturepath|textureid|nil, width:number?, height:number?, layer:drawlayer?, coords:table?, member:string?, name:string?) : df_image +---@field CreateImage fun(self:table, parent:frame, texture:atlasname|texturepath|textureid|nil, width:number?, height:number?, layer:drawlayer?, coords:table?, member:string?, name:string?) : df_image +---@field CreateFrameShake fun(self:table, parent:uiobject, duration:number?, amplitude:number?, frequency:number?, absoluteSineX:boolean?, absoluteSineY:boolean?, scaleX:number?, scaleY:number?, fadeInTime:number?, fadeOutTime:number?, anchorPoints:table?) : df_frameshake +---@field SetTexCoordFromAtlasInfo fun(self:table, texture:texture, atlasInfo:atlasinfo) : nil +---@field TruncateNumber fun(self:table, number:number, fractionDigits:number) : number +---@field GetNpcIdFromGuid fun(self:table, GUID:string) : number +---@field SortOrder1 fun(t1:table, t2:table) : boolean +---@field SortOrder2 fun(t1:table, t2:table) : boolean +---@field SortOrder3 fun(t1:table, t2:table) : boolean +---@field SortOrder1R fun(t1:table, t2:table) : boolean +---@field SortOrder2R fun(t1:table, t2:table) : boolean +---@field SortOrder3R fun(t1:table, t2:table) : boolean +---@field Trim fun(self:table, string:string) : string +---@field trim fun(self:table, string:string) : string +---@field TruncateTextBinarySearch fun(self:table, fontString:fontstring, maxWidth:number) : nil +---@field TruncateTextSafeBinarySearch fun(self:table, fontString:fontstring, maxWidth:number) : nil +---@field TruncateTextSafe fun(self:table, fontString:fontstring, maxWidth:number) : nil +---@field TruncateText fun(self:table, fontString:fontstring, maxWidth:number) : nil +---@field CleanTruncateUTF8String fun(self:table, text:string) : string +---@field GetSpellBookSpells fun(self:table) : table, spellid[] return a list of spells from the player spellbook +---@field PreviewTexture fun(self:table, texture:atlasname|texturepath|textureid, left:number?, right:number?, top:number?, bottom:number?) : nil +---@field SetAtlas fun(self:table, textureObject:texture, atlas:atlasinfo|atlasname, useAtlasSize:boolean?, filterMode:texturefilter?, resetTexCoords:boolean?) : nil +---@field CreateAtlas fun(self:table, file:texturepath|textureid, width:number?, height:number?, leftTexCoord:number?, rightTexCoord:number?, topTexCoord:number?, bottomTexCoord:number?, tilesHorizontally:boolean?, tilesVertically:boolean?, vertexRed:any, vertexGreen:number?, vertexBlue:number?, vertexAlpha:number?, desaturated:boolean?, desaturation:number?, alpha:number) : atlasinfo +---@field ParseTexture fun(self:table, texture:texturepath|textureid|atlasname|atlasinfo, width: number?, height: number?, leftTexCoord: number?, rightTexCoord: number?, topTexCoord: number?, bottomTexCoord: number?, vertexRed:number|string?, vertexGreenvertexRed:number?, vertexBluevertexRed:number?, vertexAlphavertexRed:number?) : any, number?, number?, number?, number?, number?, number?, number?, number?, number?, number?, number?, number? +---@field IsTexture fun(self:table, texture:any, bCheckTextureObject: boolean?) : boolean +---@field CreateAtlasString fun(self:table, atlas:atlasinfo|atlasname, textureHeight:number?, textureWidth:number?) : string +---@field SetMask fun(self:table, texture:texture, maskTexture:atlasname|texturepath|textureid) : nil +---@field GetClientRegion fun(self:table) : string +---@field GetBestFontPathForLanguage fun(self:table, languageId:string) : string +---@field SetTemplate fun(self:table, frame:uiobject, template:string) +---@field ParseTemplate fun(self:table, templateCategory:string, template:string|table) : table +---@field GetParentName fun(self:table, frame:uiobject) : string +---@field IsLatinLanguage fun(self:table, languageId:string) : boolean +---@field PrintVersion fun(self:table) : nil print to chat the version of the framework +---@field GetParentKeyPath fun(self:table, object:uiobject) : string +---@field GetParentNamePath fun(self:table, object:uiobject) : string +---@field GetAsianNumberSymbols fun(self:table) : string, string, string return the abbreviation for 1,000 10,000 and 100,000,000 +---@field GetBestFontForLanguage fun(self:table, languageId:string?, western:string?, cyrillic:string?, china:string? korean:string?, taiwan:string?) : string +---@field CreateGlowOverlay fun(self:table, parent:frame, antsColor:any, glowColor:any) : frame +---@field CreateAnts fun(self:table, parent:frame, antTable:df_anttable, leftOffset:number?, rightOffset:number?, topOffset:number?, bottomOffset:number?) : frame +---@field CreateBorder fun(self:table, parent:frame, alpha1:number?, alpha2:number?, alpha3:number?) : frame +---@field +---@field +---@field + + + + +--[=[ + Wrapped objects: when using the following functions, the object will be wrapped in a table, e.g. detailsFramework:CreateButton() will return a table with the button, the button will be accessible through the "button" key. + The wrapper table will have the same metatable as the wrapped object, so you can call methods on the wrapper table as if it was the wrapped object. + Example: local myButton = detailsFramework:CreateButton(); myButton:SetSize(100, 100) => will call SetSize(100, 100) on the button wrapped. + The wrapped object will be accessible through the "widget" key, e.g. local myButton = detailsFramework:CreateButton(); local actualButtonUIObject = myButton.widget. + Wrapped objects can give errors when used in some situations, like when passing them to the game API, in this case, you can use the "widget" key to access the actual object. This is very common on SetPoint calls where the game API expects a frame, not a table. Error exammple with SetPoints: "SetPoint(): Wrong object type for function". + The following functions will return a wrapped object: + - CreateButton, NewButton + - CreateColorPickButton + - CreateTexture, CreateImage, NewImage + - CreateSearchBox, NewSpellEntry, NewTextEntry, CreateTextEntry + - NewDropDown, CreateDropDown, CreateFontDropDown, CreateColorDropDown, CreateOutlineDropDown, CreateAnchorPointDropDown + - NewPanel, CreatePanel + - CreateSwitch, NewSwitch, NewSlider, CreateSlider + - NewLabel, CreateLabel + - NewSplitBar, CreateSplitBar + - CreateTimeBar +--]=] \ No newline at end of file diff --git a/libs/DF/dropdown.lua b/libs/DF/dropdown.lua index c09c479d..58628d10 100644 --- a/libs/DF/dropdown.lua +++ b/libs/DF/dropdown.lua @@ -303,7 +303,7 @@ function DropDownMetaFunctions:GetFrameForOption(optionsTable, value) --not test end function DropDownMetaFunctions:Refresh() - local optionsTable = DF:Dispatch(self.func, self) + local state, optionsTable = xpcall(self.func, geterrorhandler(), self) if (#optionsTable == 0) then self:NoOption(true) @@ -558,9 +558,11 @@ function DropDownMetaFunctions:Selected(thisOption) self.statusbar:SetTexture(thisOption.statusbar) if (thisOption.statusbarcolor) then self.statusbar:SetVertexColor(unpack(thisOption.statusbarcolor)) + else + self.statusbar:SetVertexColor(1, 1, 1, 1) end else - self.statusbar:SetTexture([[Interface\Tooltips\CHATBUBBLE-BACKGROUND]]) + self.statusbar:SetVertexColor(0, 0, 0, 0) end if (self.widget.__rcorners) then @@ -774,9 +776,11 @@ function DetailsFrameworkDropDownOnMouseDown(button, buttontype) thisOptionFrame.statusbar:SetTexture(thisOption.statusbar) if (thisOption.statusbarcolor) then thisOptionFrame.statusbar:SetVertexColor(unpack(thisOption.statusbarcolor)) + else + thisOptionFrame.statusbar:SetVertexColor(1, 1, 1, 1) end else - thisOptionFrame.statusbar:SetTexture([[Interface\Tooltips\CHATBUBBLE-BACKGROUND]]) + thisOptionFrame.statusbar:SetVertexColor(0, 0, 0, 0) end --an extra button in the right side of the row @@ -824,7 +828,7 @@ function DetailsFrameworkDropDownOnMouseDown(button, buttontype) end selectedTexture:Show() - selectedTexture:SetVertexColor(1, 1, 1, .3) + selectedTexture:SetVertexColor(1, 1, 0, .5) selectedTexture:SetTexCoord(0, 29/32, 5/32, 27/32) currentIndex = tindex @@ -992,7 +996,7 @@ function DetailsFrameworkDropDownOnHide(self) end local iconSizeTable = {16, 16} -function DF:BuildDropDownFontList(onClick, icon, iconTexcoord, iconSize) +function DF:BuildDropDownFontList(onClick, icon, iconTexcoord, iconSize, bIncludeDefault) local fontTable = {} local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0") @@ -1002,6 +1006,10 @@ function DF:BuildDropDownFontList(onClick, icon, iconTexcoord, iconSize) table.sort(fontTable, function(t1, t2) return t1.label < t2.label end) + if (bIncludeDefault) then + table.insert(fontTable, 1, {value = "DEFAULT", label = "DEFAULT", onclick = onClick, icon = icon, iconsize = iconSizeTable, texcoord = iconTexcoord, font = "", descfont = "abcdefg ABCDEFG"}) + end + return fontTable end @@ -1009,13 +1017,15 @@ end --template function DropDownMetaFunctions:SetTemplate(template) + template = DF:ParseTemplate(self.type, template) + self.template = template if (template.width) then PixelUtil.SetWidth(self.dropdown, template.width) end if (template.height) then - PixelUtil.SetWidth(self.dropdown, template.height) + PixelUtil.SetHeight(self.dropdown, template.height) end if (template.backdrop) then @@ -1089,20 +1099,26 @@ end ------------------------------------------------------------------------------------------------------------ --object constructor ----@class df_dropdown : table, frame ----@field SetTemplate fun(self:df_dropdown, template:table) +---@class df_dropdown : table, frame, df_widgets +---@field SetTemplate fun(self:df_dropdown, template:table|string) ---@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 ----@field ----@field ----@field ----@field +---@field SetFunction fun(self:df_dropdown, func:function) +---@field SetEmptyTextAndIcon fun(self:df_dropdown, text:string, icon:any) +---@field Select fun(self:df_dropdown, optionName:string|number, byOptionNumber:boolean?, bOnlyShown:boolean?, runCallback:boolean?):boolean +---@field Open fun(self:df_dropdown) +---@field Close fun(self:df_dropdown) +---@field Refresh fun(self:df_dropdown) +---@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) +---@field Disable fun(self:df_dropdown) +---@field Enable fun(self:df_dropdown) ---return a function which when called returns a table filled with all fonts available and ready to be used on dropdowns ---@param callback function ---@return function -function DF:CreateFontListGenerator(callback) - return function() return DF:BuildDropDownFontList(callback, [[Interface\AnimCreate\AnimCreateIcons]], {0, 32/128, 64/128, 96/128}, 16) end +function DF:CreateFontListGenerator(callback, bIncludeDefault) + return function() return DF:BuildDropDownFontList(callback, [[Interface\AnimCreate\AnimCreateIcons]], {0, 32/128, 64/128, 96/128}, 16, bIncludeDefault) end end local colorGeneratorStatusBarTexture = [[Interface\Tooltips\UI-Tooltip-Background]] @@ -1186,8 +1202,9 @@ end ---@param member string? ---@param name string? ---@param template table? -function DF:CreateFontDropDown(parent, callback, default, width, height, member, name, template) - local func = DF:CreateFontListGenerator(callback) +---@param bIncludeDefault boolean? +function DF:CreateFontDropDown(parent, callback, default, width, height, member, name, template, bIncludeDefault) + local func = DF:CreateFontListGenerator(callback, bIncludeDefault) local dropDownObject = DF:NewDropDown(parent, parent, name, member, width, height, func, default, template) return dropDownObject end @@ -1238,7 +1255,7 @@ function DF:NewDropDown(parent, container, name, member, width, height, func, de end if (name:find("$parent")) then - local parentName = DF.GetParentName(parent) + local parentName = DF:GetParentName(parent) name = name:gsub("$parent", parentName) end @@ -1259,6 +1276,9 @@ function DF:NewDropDown(parent, container, name, member, width, height, func, de default = 1 end + width = width or 160 + height = height or 20 + dropDownObject.dropdown = DF:CreateNewDropdownFrame(parent, name) PixelUtil.SetSize(dropDownObject.dropdown, width, height) diff --git a/libs/DF/frames.lua b/libs/DF/frames.lua index 4b5f698f..df652a32 100644 --- a/libs/DF/frames.lua +++ b/libs/DF/frames.lua @@ -14,86 +14,6 @@ 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 diff --git a/libs/DF/fw.lua b/libs/DF/fw.lua index 5b3a9a20..76f1d8d7 100644 --- a/libs/DF/fw.lua +++ b/libs/DF/fw.lua @@ -1,6 +1,6 @@ -local dversion = 510 +local dversion = 525 local major, minor = "DetailsFramework-1.0", dversion local DF, oldminor = LibStub:NewLibrary(major, minor) @@ -13,17 +13,14 @@ _G["DetailsFramework"] = DF ---@cast DF detailsframework +local detailsFramework = DF + DetailsFrameworkCanLoad = true local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0") local _ local type = type local unpack = unpack -local upper = string.upper -local string_match = string.match -local tinsert = table.insert -local abs = _G.abs -local tremove = _G.tremove local IS_WOW_PROJECT_MAINLINE = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE local IS_WOW_PROJECT_NOT_MAINLINE = WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE @@ -34,6 +31,8 @@ local UnitIsTapDenied = UnitIsTapDenied SMALL_NUMBER = 0.000001 ALPHA_BLEND_AMOUNT = 0.8400251 +local _, _, _, buildInfo = GetBuildInfo() + DF.dversion = dversion DF.AuthorInfo = { @@ -80,62 +79,104 @@ function DF:GetDefaultBackdropColor() return 0.1215, 0.1176, 0.1294, 0.8 end ----return if the wow version the player is playing is dragonflight or an expansion after it ----@return boolean -function DF.IsDragonflightAndBeyond() - return select(4, GetBuildInfo()) >= 100000 -end - ---return if the wow version the player is playing is dragonflight ---@return boolean function DF.IsDragonflight() - local _, _, _, buildInfo = GetBuildInfo() - if (buildInfo < 110000 and buildInfo >= 100000) then - return true - end + if (buildInfo < 110000 and buildInfo >= 100000) then return true end return false end +---return if the wow version the player is playing is dragonflight or an expansion after it +---@return boolean +function DF.IsDragonflightAndBeyond() + return select(4, GetBuildInfo()) >= 100000 +end + ---return if the wow version the player is playing is a classic version of wow ---@return boolean function DF.IsTimewalkWoW() - local _, _, _, buildInfo = GetBuildInfo() - if (buildInfo < 40000) then - return true - end + if (buildInfo < 40000) then return true end return false end ---return if the wow version the player is playing is the vanilla version of wow ---@return boolean function DF.IsClassicWow() - local _, _, _, buildInfo = GetBuildInfo() - if (buildInfo < 20000) then - return true - end + if (buildInfo < 20000) then return true end return false end ---return true if the player is playing in the TBC version of wow ---@return boolean function DF.IsTBCWow() - local _, _, _, buildInfo = GetBuildInfo() - if (buildInfo < 30000 and buildInfo >= 20000) then - return true - end + if (buildInfo < 30000 and buildInfo >= 20000) then return true end return false end ---return true if the player is playing in the WotLK version of wow ---@return boolean function DF.IsWotLKWow() - local _, _, _, buildInfo = GetBuildInfo() - if (buildInfo < 40000 and buildInfo >= 30000) then - return true - end + if (buildInfo < 40000 and buildInfo >= 30000) then return true end + return false +end + +---return true if the player is playing in the Cataclysm version of wow +---@return boolean +function DF.IsCataWow() + if (buildInfo < 50000 and buildInfo >= 40000) then return true end + return false +end + +---return true if the player is playing in the Mists version of wow +---@return boolean +function DF.IsPandaWow() + if (buildInfo < 60000 and buildInfo >= 50000) then return true end + return false +end + +---return true if the player is playing in the Warlords of Draenor version of wow +---@return boolean +function DF.IsWarlordsWow() + if (buildInfo < 70000 and buildInfo >= 60000) then return true end + return false +end + +---return true if the player is playing in the Legion version of wow +---@return boolean +function DF.IsLegionWow() + if (buildInfo < 80000 and buildInfo >= 70000) then return true end + return false +end + +---return true if the player is playing in the BFA version of wow +---@return boolean +function DF.IsBFAWow() + if (buildInfo < 90000 and buildInfo >= 80000) then return true end + return false +end + +---return true if the player is playing in the Shadowlands version of wow +---@return boolean +function DF.IsShadowlandsWow() + if (buildInfo < 100000 and buildInfo >= 90000) then return true end return false end +---return if the wow version the player is playing is dragonflight +---@return boolean +function DF.IsDragonflightWow() + if (buildInfo < 110000 and buildInfo >= 100000) then return true end + return false +end + +---return if the wow version the player is playing is the war within +---@return boolean +function DF.IsWarWow() + if (buildInfo < 120000 and buildInfo >= 110000) then return true end + return false +end + + ---return true if the player is playing in the WotLK version of wow with the retail api ---@return boolean function DF.IsNonRetailWowWithRetailAPI() @@ -218,7 +259,7 @@ function DF:GetRoleByClassicTalentTree() --tab information local name, iconTexture, pointsSpent, fileName = GetTalentTabInfo(i) if (name) then - tinsert(pointsPerSpec, {name, pointsSpent, fileName}) + table.insert(pointsPerSpec, {name, pointsSpent, fileName}) end end end @@ -458,7 +499,6 @@ local embedFunctions = { "NewSpecialLuaEditorEntry", "ShowPromptPanel", "ShowTextPromptPanel", - "www_icons", "GetTemplate", "InstallTemplate", "GetFrameworkFolder", @@ -522,6 +562,10 @@ function DF:RandomBool(odds) end end +function DF:SetTexCoordFromAtlasInfo(texture, atlasInfo) + texture:SetTexCoord(atlasInfo.leftTexCoord, atlasInfo.rightTexCoord, atlasInfo.topTexCoord, atlasInfo.bottomTexCoord) +end + ------------------------------------------------------------------------------------------------------------ --table @@ -553,7 +597,11 @@ function DF.table.findsubtable(t, index, value) end end - +---Loop through parent of the passed object, making a string with parentKeys separated by a dot. +---The loop continues until a parentKey is not found or if the frame has no parent (reach UIParent). +---@param self table +---@param object any +---@return string function DF:GetParentKeyPath(object) local parentKey = object:GetParentKey() if (not parentKey) then @@ -578,6 +626,11 @@ function DF:GetParentKeyPath(object) return path end +---Loop through the parent of the passed object, creating a string with parent names and parent keys separated by dots, if the object has no name. +---The loop continues until a parentName is not found or if the frame has no parent (reach UIParent). +---@param self table +---@param object any +---@return string function DF:GetParentNamePath(object) local parent = object local path = "" @@ -591,7 +644,8 @@ function DF:GetParentNamePath(object) if (parentKey) then parentName = parentKey else - return path:gsub("%.$", "") + local result = path:gsub("%.$", "") + return result end end end @@ -599,13 +653,15 @@ function DF:GetParentNamePath(object) if (parentName) then path = parentName .. "." .. path else - return path:gsub("%.$", "") + local result = path:gsub("%.$", "") + return result end parent = parent:GetParent() end - return path:gsub("%.$", "") + local result = path:gsub("%.$", "") + return result end ---get a value from a table using a path, e.g. getfrompath(tbl, "a.b.c") is the same as tbl.a.b.c @@ -688,7 +744,7 @@ function DF.table.addunique(t, index, value) end end - tinsert(t, index, value) + table.insert(t, index, value) return true end @@ -898,53 +954,7 @@ end ---@param deep integer ---@return string function DF.table.dump(t, resultString, deep) - - if true then return tableToStringSafe(t) end - - resultString = resultString or "" - deep = deep or 0 - local space = "" - for i = 1, deep do - space = space .. " " - end - - for key, value in pairs(t) do - local valueType = type(value) - - if (type(key) == "function") then - key = "#function#" - elseif (type(key) == "table") then - key = "#table#" - end - - if (type(key) ~= "string" and type(key) ~= "number") then - key = "unknown?" - end - - if (valueType == "table") then - if (type(key) == "number") then - resultString = resultString .. space .. "[" .. key .. "] = |cFFa9ffa9 {|r\n" - else - resultString = resultString .. space .. "[\"" .. key .. "\"] = |cFFa9ffa9 {|r\n" - end - resultString = resultString .. DF.table.dump (value, nil, deep+1) - resultString = resultString .. space .. "|cFFa9ffa9},|r\n" - - elseif (valueType == "string") then - resultString = resultString .. space .. "[\"" .. key .. "\"] = \"|cFFfff1c1" .. value .. "|r\",\n" - - elseif (valueType == "number") then - resultString = resultString .. space .. "[\"" .. key .. "\"] = |cFFffc1f4" .. value .. "|r,\n" - - elseif (valueType == "function") then - resultString = resultString .. space .. "[\"" .. key .. "\"] = function()end,\n" - - elseif (valueType == "boolean") then - resultString = resultString .. space .. "[\"" .. key .. "\"] = |cFF99d0ff" .. (value and "true" or "false") .. "|r,\n" - end - end - - return resultString + return tableToStringSafe(t) end ---grab a text and split it into lines adding each line to an array table @@ -957,14 +967,14 @@ function DF:SplitTextInLines(text) while (startScope) do if (startScope ~= 1) then - tinsert(lines, text:sub(position, startScope-1)) + table.insert(lines, text:sub(position, startScope-1)) end position = endScope + 1 startScope, endScope = text:find("\n", position, true) end if (position <= #text) then - tinsert(lines, text:sub(position)) + table.insert(lines, text:sub(position)) end return lines @@ -1007,13 +1017,6 @@ function DF.strings.stringtotable(thisString, bDoCompression) return newTable end -DF.www_icons = { - texture = "feedback_sites", - wowi = {0, 0.7890625, 0, 37/128}, - curse = {0, 0.7890625, 38/123, 79/128}, - mmoc = {0, 0.7890625, 80/123, 123/128}, -} - local symbol_1K, symbol_10K, symbol_1B if (GetLocale() == "koKR") then symbol_1K, symbol_10K, symbol_1B = "천", "만", "억" @@ -1095,7 +1098,7 @@ function DF:CommaValue(value) end --source http://richard.warburton.it - local left, num, right = string_match (value, '^([^%d]*%d)(%d*)(.-)$') + local left, num, right = string.match(value, '^([^%d]*%d)(%d*)(.-)$') return left .. (num:reverse():gsub('(%d%d%d)','%1,'):reverse()) .. right end @@ -1162,6 +1165,8 @@ function DF:CleanUpName(name) name = DF:RemoveRealmName(name) name = DF:RemoveOwnerName(name) name = name:gsub("%[%*%]%s", "") + --remove texture escape sequence + name = name:gsub("|T.-|t", "") return name end @@ -1187,6 +1192,11 @@ end ---@param fontString fontstring ---@param fontface string function DF:SetFontFace(fontString, fontface) + if (fontface == "DEFAULT") then + DF:SetFontDefault(fontString) + return + end + local font = SharedMedia:Fetch("font", fontface, true) if (font) then fontface = font @@ -1196,6 +1206,17 @@ function DF:SetFontFace(fontString, fontface) return fontString:SetFont(fontface, size, flags) end +local dummyFontString = UIParent:CreateFontString(nil, "background", "GameFontNormal") +local defaultFontFile = dummyFontString:GetFont() + +---get the UIObject of type 'FontString' and set the default game font into it +---@param self table +---@param fontString fontstring +function DF:SetFontDefault(fontString) + local _, size, flags = fontString:GetFont() + return fontString:SetFont(defaultFontFile, size, flags) +end + ---get the FontString passed and set the font color ---@param self table ---@param fontString fontstring @@ -1353,7 +1374,7 @@ function DF:AddClassIconToText(text, playerName, englishClassName, useSpec, icon return text end ----create a table with information about a texture +---create a table with information about a texture (deprecated, use: DetailsFramework:CreateAtlas()) ---@param texture any ---@param textureWidth any ---@param textureHeight any @@ -1426,10 +1447,12 @@ local ValidOutlines = { ["MONOCHROME"] = true, ["OUTLINE"] = true, ["THICKOUTLINE"] = true, + ["OUTLINEMONOCHROME"] = true, + ["THICKOUTLINEMONOCHROME"] = true, } DF.FontOutlineFlags = { - {"NONE", "None"}, + {"", "None"}, {"MONOCHROME", "Monochrome"}, {"OUTLINE", "Outline"}, {"THICKOUTLINE", "Thick Outline"}, @@ -1439,33 +1462,34 @@ DF.FontOutlineFlags = { ---set the outline of a fontstring, outline is a black border around the text, can be "NONE", "MONOCHROME", "OUTLINE" or "THICKOUTLINE" ---@param fontString table ----@param outline any +---@param outline outline function DF:SetFontOutline(fontString, outline) - local font, fontSize = fontString:GetFont() - if (outline) then - if (type(outline) == "string") then - outline = outline:upper() - end + local font, fontSize = fontString:GetFont() + if (outline) then + if (type(outline) == "string") then + outline = outline:upper() + end - if (ValidOutlines[outline]) then - outline = outline + if (ValidOutlines[outline]) then + outline = outline - elseif (type(outline) == "boolean" and outline) then - outline = "OUTLINE" + elseif (type(outline) == "boolean" and outline) then + outline = "OUTLINE" - elseif (type(outline) == "boolean" and not outline) then - outline = "" --"NONE" + elseif (type(outline) == "boolean" and not outline) then + outline = "" --"NONE" - elseif (outline == 1) then - outline = "OUTLINE" + elseif (outline == 1) then + outline = "OUTLINE" - elseif (outline == 2) then - outline = "THICKOUTLINE" - end - end - outline = (not outline or outline == "NONE") and "" or outline + elseif (outline == 2) then + outline = "THICKOUTLINE" + end + end - fontString:SetFont(font, fontSize, outline) + outline = (not outline or outline == "NONE") and "" or outline + + fontString:SetFont(font, fontSize, outline) end ---remove spaces from the start and end of the string @@ -1522,6 +1546,67 @@ function DF:TruncateText(fontString, maxWidth) fontString:SetText(text) end +---truncate removing text through a binary search with a max of 10 iterations +---@param fontString table +---@param maxWidth number +function DF:TruncateTextSafeBinarySearch(fontString, maxWidth) + local text = fontString:GetText() + if text == nil or text == '' then return end + + if fontString:GetUnboundedStringWidth() > maxWidth then + local left = 1 + local right = #text + local numIterations = 10 + + while left <= right and numIterations > 0 do + local middle = math.floor((left + right) * 0.5) + local substring = strsub(text, 1, middle) + fontString:SetText(substring) + + if fontString:GetUnboundedStringWidth() <= maxWidth then + left = middle + 1 + else + right = middle - 1 + end + + numIterations = numIterations - 1 + end + + text = strsub(text, 1, right) + end + + fontString:SetText(DF:CleanTruncateUTF8String(text)) +end + +---truncate removing characters from the string until the maxWidth is reach +---@param fontString table +---@param maxWidth number +function DF:TruncateTextBinarySearch(fontString, maxWidth) + local text = fontString:GetText() + if text == nil or text == '' then return end + + if fontString:GetUnboundedStringWidth() > maxWidth then + local left = 1 + local right = #text + + while left <= right do + local middle = math.floor((left + right) * 0.5) + local substring = strsub(text, 1, middle) + fontString:SetText(substring) + + if fontString:GetUnboundedStringWidth() <= maxWidth then + left = middle + 1 + else + right = middle - 1 + end + end + + text = strsub(text, 1, right) + end + + fontString:SetText(DF:CleanTruncateUTF8String(text)) +end + ---@param text string ---@return string function DF:CleanTruncateUTF8String(text) @@ -1595,7 +1680,9 @@ function DF.SortOrder3R(t1, t2) return t1[3] < t2[3] end ---return a list of spells from the player spellbook +---return a list of spells from the player spellbook +---@return table spellNamesInSpellBook +---@return spellid[] spellIdsInSpellBook function DF:GetSpellBookSpells() local spellNamesInSpellBook = {} local spellIdsInSpellBook = {} @@ -2032,10 +2119,15 @@ end ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --colors - --add a new color name, the color can be query using DetailsFramework:ParseColors(colorName) + ---add a new color name, the color can be query using DetailsFramework:ParseColors(colorName) + ---@param colorName string + ---@param red number + ---@param green number + ---@param blue number + ---@param alpha number? + ---@return table function DF:NewColor(colorName, red, green, blue, alpha) assert(type(colorName) == "string", "DetailsFramework:NewColor(): colorName must be a string.") - --assert(not DF.alias_text_colors[colorName], "DetailsFramework:NewColor(): colorName already exists.") red, green, blue, alpha = DetailsFramework:ParseColors(red, green, blue, alpha) local colorTable = DetailsFramework:FormatColor("table", red, green, blue, alpha) @@ -2061,16 +2153,16 @@ end IsColorTable = true, } - --takes in a color in one format and converts it to another specified format. - --here are the parameters it accepts: - --newFormat (string): The format to convert the color to. It can be one of the following: "commastring", "tablestring", "table", "tablemembers", "numbers", "hex". - --r (number|string): The red component of the color or a string representing the color. - --g (number|nil): The green component of the color. This is optional if r is a string. - --b (number|nil): The blue component of the color. This is optional if r is a string. - --a (number|nil): The alpha component of the color. This is optional and defaults to 1 if not provided. - --decimalsAmount (number|nil): The number of decimal places to round the color components to. This is optional and defaults to 4 if not provided. - --The function returns the color in the new format. The return type depends on the newFormat parameter. It can be a string, a table, or four separate number values (for the "numbers" format). - --For the "hex" format, it returns a string representing the color in hexadecimal format. + ---* takes in a color in one format and converts it to another specified format. + ---* here are the parameters it accepts: + ---* newFormat (string): The format to convert the color to. It can be one of the following: "commastring", "tablestring", "table", "tablemembers", "numbers", "hex". + ---* r (number|string): The red component of the color or a string representing the color. + ---* g (number|nil): The green component of the color. This is optional if r is a string. + ---* b (number|nil): The blue component of the color. This is optional if r is a string. + ---* a (number|nil): The alpha component of the color. This is optional and defaults to 1 if not provided. + ---* decimalsAmount (number|nil): The number of decimal places to round the color components to. This is optional and defaults to 4 if not provided. + ---* The function returns the color in the new format. The return type depends on the newFormat parameter. It can be a string, a table, or four separate number values (for the "numbers" format). + ---* For the "hex" format, it returns a string representing the color in hexadecimal format. ---@param newFormat string ---@param r number|string ---@param g number|nil @@ -2271,12 +2363,12 @@ end TutorialAlertFrame:Show() end - function DF:CreateOptionsFrame(name, title, template) + function DF:CreateOptionsFrame(name, title, template) --deprecated? template = template or 1 if (template == 2) then local newOptionsFrame = CreateFrame("frame", name, UIParent, "ButtonFrameTemplate") - tinsert(UISpecialFrames, name) + table.insert(UISpecialFrames, name) newOptionsFrame:SetSize(500, 200) newOptionsFrame.RefreshOptions = DF.internalFunctions.RefreshOptionsPanel @@ -2314,7 +2406,7 @@ end elseif (template == 1) then local newOptionsFrame = CreateFrame("frame", name, UIParent) - tinsert(UISpecialFrames, name) + table.insert(UISpecialFrames, name) newOptionsFrame:SetSize(500, 200) newOptionsFrame.RefreshOptions = DF.internalFunctions.RefreshOptionsPanel @@ -2404,13 +2496,8 @@ end DF.ClientLanguage = clientLanguage -function DF:DetectTextLanguage(text) - for i = 1, #text do - --or not - end -end - ---returns which region the language the client is running, return "western", "russia" or "asia" +---returns which region the language the client is running, return "western", "russia" or "asia" +---@return string function DF:GetClientRegion() if (clientLanguage == "zhCN" or clientLanguage == "koKR" or clientLanguage == "zhTW") then return "asia" @@ -2422,7 +2509,11 @@ function DF:GetClientRegion() end DF.registeredFontPaths = DF.registeredFontPaths or {} + -- ~language ~locale ~fontpath +---get a font path to be used for a specific language +---@param languageId string enUS, deDE, esES, esMX, frFR, itIT, ptBR, ruRU, zhCN, zhTW, koKR +---@return string function DF:GetBestFontPathForLanguage(languageId) local fontPath = DF.registeredFontPaths[languageId] if (fontPath) then @@ -2450,11 +2541,21 @@ function DF:GetBestFontPathForLanguage(languageId) return [[Fonts\FRIZQT__.TTF]] end +---return true if the language paren is latin: enUS, deDE, esES, esMX, frFR, itIT, ptBR +---@param languageId string +---@return boolean function DF:IsLatinLanguage(languageId) return latinLanguageIdsMap[languageId] end ---return the best font to use for the client language +---return a font name to use for the client language +---@param self table +---@param languageId string? +---@param western string? +---@param cyrillic string? +---@param china string? +---@param korean string? +---@param taiwan string? function DF:GetBestFontForLanguage(languageId, western, cyrillic, china, korean, taiwan) if (not languageId) then languageId = DF.ClientLanguage @@ -2477,6 +2578,137 @@ function DF:GetBestFontForLanguage(languageId, western, cyrillic, china, korean, end end + +local templateOnEnter = function(frame) + if (frame.onenter_backdrop) then + local r, g, b, a = detailsFramework:ParseColors(frame.onenter_backdrop) + frame:SetBackdropColor(r, g, b, a) + end + if (frame.onenter_backdrop_border_color) then + local r, g, b, a = detailsFramework:ParseColors(frame.onenter_backdrop_border_color) + frame:SetBackdropBorderColor(r, g, b, a) + end +end + +local templateOnLeave = function(frame) + if (frame.onleave_backdrop) then + local r, g, b, a = detailsFramework:ParseColors(frame.onleave_backdrop) + frame:SetBackdropColor(r, g, b, a) + end + if (frame.onleave_backdrop_border_color) then + local r, g, b, a = detailsFramework:ParseColors(frame.onleave_backdrop_border_color) + frame:SetBackdropBorderColor(r, g, b, a) + end +end + +---set a details framework template into a regular frame +---@param self table +---@param frame uiobject +---@param template string +function detailsFramework:SetTemplate(frame, template) + template = detailsFramework:ParseTemplate("button", template) + + if (frame.SetWidth) then + if (template.width) then + PixelUtil.SetWidth(frame, template.width) + end + + if (template.height) then + PixelUtil.SetHeight(frame, template.height) + end + end + + if (frame.SetBackdrop) then + if (template.backdrop) then + frame:SetBackdrop(template.backdrop) + end + + if (template.backdropcolor) then + local r, g, b, a = detailsFramework:ParseColors(template.backdropcolor) + frame:SetBackdropColor(r, g, b, a) + frame.onleave_backdrop = {r, g, b, a} + end + + if (template.backdropbordercolor) then + local r, g, b, a = detailsFramework:ParseColors(template.backdropbordercolor) + frame:SetBackdropBorderColor(r, g, b, a) + frame.onleave_backdrop_border_color = {r, g, b, a} + end + + if (template.onentercolor) then + local r, g, b, a = detailsFramework:ParseColors(template.onentercolor) + frame.onenter_backdrop = {r, g, b, a} + frame:HookScript("OnEnter", templateOnEnter) + frame.__has_onentercolor_script = true + end + + if (template.onleavecolor) then + local r, g, b, a = detailsFramework:ParseColors(template.onleavecolor) + frame.onleave_backdrop = {r, g, b, a} + frame:HookScript("OnLeave", templateOnLeave) + frame.__has_onleavecolor_script = true + end + + if (template.onenterbordercolor) then + local r, g, b, a = detailsFramework:ParseColors(template.onenterbordercolor) + frame.onenter_backdrop_border_color = {r, g, b, a} + if (not frame.__has_onentercolor_script) then + frame:HookScript("OnEnter", templateOnEnter) + end + end + + if (template.onleavebordercolor) then + local r, g, b, a = detailsFramework:ParseColors(template.onleavebordercolor) + frame.onleave_backdrop_border_color = {r, g, b, a} + if (not frame.__has_onleavecolor_script) then + frame:HookScript("OnLeave", templateOnLeave) + end + end + + elseif (frame.SetColorTexture) then + if (template.backdropcolor) then + local r, g, b, a = detailsFramework:ParseColors(template.backdropcolor) + frame:SetColorTexture(r, g, b, a) + end + end + + if (frame.SetIcon) then + if (template.icon) then + local iconInfo = template.icon + frame:SetIcon(iconInfo.texture, iconInfo.width, iconInfo.height, iconInfo.layout, iconInfo.texcoord, iconInfo.color, iconInfo.textdistance, iconInfo.leftpadding) + end + end + + if (frame.SetTextColor) then + if (template.textsize) then + detailsFramework:SetFontSize(frame, template.textsize) + end + + if (template.textfont) then + detailsFramework:SetFontFace(frame, template.textfont) + end + + if (template.textcolor) then + detailsFramework:SetFontColor(frame, template.textcolor) + end + + --horizontal alignment + if (template.textalign and frame.SetJustifyH) then + template.textalign = string.lower(template.textalign) + + if (template.textalign == "left" or template.textalign == "<") then + frame:SetJustifyH("LEFT") + + elseif (template.textalign == "center" or template.textalign == "|") then + frame:SetJustifyH("CENTER") + + elseif (template.textalign == "right" or template.textalign == ">") then + frame:SetJustifyH("RIGHT") + end + end + end +end + --DF.font_templates ["ORANGE_FONT_TEMPLATE"] = {color = "orange", size = 11, font = "Accidental Presidency"} --DF.font_templates ["OPTIONS_FONT_TEMPLATE"] = {color = "yellow", size = 12, font = "Accidental Presidency"} DF.font_templates["ORANGE_FONT_TEMPLATE"] = {color = "orange", size = 10, font = DF:GetBestFontForLanguage()} @@ -2522,6 +2754,28 @@ DF.dropdown_templates["OPTIONS_DROPDOWNDARK_TEMPLATE"] = { dropiconpoints = {-2, -3}, } +DF.dropdown_templates["OLD_DROPDOWN_TEMPLATE"] = { + height = 24, + + backdrop = { + edgeFile = "Interface\\Buttons\\UI-SliderBar-Border", + edgeSize = 8, + bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], + tileSize = 64, + tile = true, + insets = {left = 4, right = 4, top = 4, bottom = 4} + }, + + backdropcolor = {0.1215, 0.1176, 0.1294, 0.4000}, + backdropbordercolor = {1, 1, 1, 1}, + onentercolor = {.5, .5, .5, .9}, + onenterbordercolor = {1, 1, 1, 1}, + + dropicon = "Interface\\BUTTONS\\arrow-Down-Down", + dropiconsize = {16, 16}, + dropiconpoints = {-2, -3}, +} + --switches DF.switch_templates = DF.switch_templates or {} DF.switch_templates["OPTIONS_CHECKBOX_TEMPLATE"] = { @@ -2534,6 +2788,23 @@ DF.switch_templates["OPTIONS_CHECKBOX_TEMPLATE"] = { disabled_backdropcolor = {1, 1, 1, .2}, onenterbordercolor = {1, 1, 1, 1}, } + +DF.switch_templates["OPTIONS_CIRCLECHECKBOX_TEMPLATE"] = { + width = 18, + height = 18, + is_checkbox = true, --will call SetAsCheckBox() + checked_texture = [[Interface\CHARACTERFRAME\TempPortraitAlphaMaskSmall]], + checked_size_percent = 0.7, + checked_xoffset = 0, + checked_yoffset = 0, + checked_color = "dark3", + rounded_corner = { + color = {.075, .075, .075, 1}, + border_color = {.2, .2, .2, 1}, + roundness = 8, + }, +} + DF.switch_templates["OPTIONS_CHECKBOX_BRIGHT_TEMPLATE"] = { backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}, backdropcolor = {1, 1, 1, .5}, @@ -2553,12 +2824,28 @@ DF.button_templates["OPTIONS_BUTTON_TEMPLATE"] = { backdropbordercolor = {0, 0, 0, 1}, } +DF.button_templates["OPTIONS_CIRCLEBUTTON_TEMPLATE"] = { + rounded_corner = { + color = {.075, .075, .075, 1}, + border_color = {.2, .2, .2, 1}, + roundness = 8, + }, +} + DF.button_templates["OPTIONS_BUTTON_GOLDENBORDER_TEMPLATE"] = { backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}, backdropcolor = {1, 1, 1, .5}, backdropbordercolor = {1, 0.785, 0, 1}, } +DF.button_templates["STANDARD_GRAY"] = { + backdrop = {edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}, + backdropcolor = {0.2, 0.2, 0.2, 0.502}, + backdropbordercolor = {0, 0, 0, 0.5}, + onentercolor = {0.4, 0.4, 0.4, 0.502}, + +} + --sliders DF.slider_templates = DF.slider_templates or {} DF.slider_templates["OPTIONS_SLIDER_TEMPLATE"] = { @@ -2573,18 +2860,80 @@ DF.slider_templates["OPTIONS_SLIDER_TEMPLATE"] = { thumbcolor = {0, 0, 0, 0.5}, } ----install a template ----@param widgetType string +DF.slider_templates["MODERN_SLIDER_TEMPLATE"] = { + thumbtexture = "Minimal_SliderBar_Button", --atlas name + thumbwidth = 20, + thumbheight = 19, + thumbcolor = {1, 1, 1, 0.924}, + slider_left = "Minimal_SliderBar_Left", + slider_right = "Minimal_SliderBar_Right", + slider_middle = "_Minimal_SliderBar_Middle", + amount_color = "white", + amount_size = 12, + amount_outline = "outline", +} + +local templateTables = {DF.dropdown_templates, DF.button_templates, DF.switch_templates, DF.slider_templates, DF.font_templates} + +---template categories: "font", "dropdown", "button", "switch", "slider" +---receives a template category and a template name or table +---if a template name has been passed, the function will iterate over all template tables to find a template with the name passed +---@param self table +---@param templateCategory templatecategory +---@param template string|table +---@return table +function DF:ParseTemplate(templateCategory, template) + if (type(template) == "string") then + local objectType = templateCategory + + if (objectType == "label") then + templateCategory = "font" + + elseif (objectType == "dropdown") then + templateCategory = "dropdown" + + elseif (objectType == "button") then + templateCategory = "button" + + elseif (objectType == "switch") then + templateCategory = "switch" + + elseif (objectType == "slider") then + templateCategory = "slider" + end + + local templateTable = DF:GetTemplate(templateCategory, template) + if (templateTable) then + return templateTable + end + + --iterate over all template tables to find a template with the name passed + for i = 1, #templateTables do + local tTable = templateTables[i] + if (tTable[template]) then + return tTable[template] + end + end + else + return template + end + + ---@cast template table + return template +end + +---register a new template to be used with SetTemplate calls +---@param templateCategory templatecategory ---@param templateName string ---@param template table ---@param parentName any ---@return table -function DF:InstallTemplate(widgetType, templateName, template, parentName) +function DF:InstallTemplate(templateCategory, templateName, template, parentName) local newTemplate = {} --if has a parent, just copy the parent to the new template if (parentName and type(parentName) == "string") then - local parentTemplate = DF:GetTemplate(widgetType, parentName) + local parentTemplate = DF:GetTemplate(templateCategory, parentName) if (parentTemplate) then DF.table.copy(newTemplate, parentTemplate) end @@ -2593,10 +2942,10 @@ function DF:InstallTemplate(widgetType, templateName, template, parentName) --copy the template passed into the new template DF.table.copy(newTemplate, template) - widgetType = string.lower(widgetType) + templateCategory = string.lower(templateCategory) local templateTable - if (widgetType == "font") then + if (templateCategory == "font") then templateTable = DF.font_templates local font = template.font @@ -2606,16 +2955,16 @@ function DF:InstallTemplate(widgetType, templateName, template, parentName) font = DF:GetBestFontForLanguage(nil, font) end - elseif (widgetType == "dropdown") then + elseif (templateCategory == "dropdown") then templateTable = DF.dropdown_templates - elseif (widgetType == "button") then + elseif (templateCategory == "button") then templateTable = DF.button_templates - elseif (widgetType == "switch") then + elseif (templateCategory == "switch") then templateTable = DF.switch_templates - elseif (widgetType == "slider") then + elseif (templateCategory == "slider") then templateTable = DF.slider_templates end @@ -2646,7 +2995,10 @@ function DF:GetTemplate(widgetType, templateName) return templateTable[templateName] end -function DF.GetParentName(frame) +---get the name of the parent of the passed frame +---@param frame frame +---@return string +function DF:GetParentName(frame) local parentName = frame:GetName() if (not parentName) then error("Details! FrameWork: called $parent but parent was no name.", 2) @@ -2654,7 +3006,7 @@ function DF.GetParentName(frame) return parentName end -function DF:Error (errortext) +function DF:Error(errortext) print("|cFFFF2222Details! Framework Error|r:", errortext, self.GetName and self:GetName(), self.WidgetType, debugstack (2, 3, 0)) end @@ -2797,9 +3149,30 @@ function DF:CreateAnimationHub(parent, onPlay, onFinished) return newAnimation end -function DF:CreateAnimation(animation, animationType, order, duration, arg1, arg2, arg3, arg4, arg5, arg6, arg7) - local anim = animation:CreateAnimation(animationType) - anim:SetOrder(order or animation.NextAnimation) +---* Create a new animation for an animation hub or group. +---* Alpha: CreateAnimation(animGroup, "Alpha", order, duration, fromAlpha, toAlpha). +---* Scale: CreateAnimation(animGroup, "Scale", order, duration, fromScaleX, fromScaleY, toScaleX, toScaleY, originPoint, x, y). +---* Translation: CreateAnimation(animGroup, "Translation", order, duration, xOffset, yOffset). +---* Rotation: CreateAnimation(animGroup, "Rotation", order, duration, degrees, originPoint, x, y). +---* Path: CreateAnimation(animGroup, "Path", order, duration, xOffset, yOffset, curveType). +---* VertexColor: CreateAnimation(animGroup, "VertexColor", order, duration, r1, g1, b1, a1, r2, g2, b2, a2). +---@param animationGroup animationgroup +---@param animationType animationtype +---@param order number +---@param duration number +---@param arg1 any +---@param arg2 any +---@param arg3 any +---@param arg4 any +---@param arg5 any +---@param arg6 any +---@param arg7 any +---@param arg8 any +---@return animation +function DF:CreateAnimation(animationGroup, animationType, order, duration, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + ---@type animation + local anim = animationGroup:CreateAnimation(animationType) + anim:SetOrder(order or animationGroup.NextAnimation) anim:SetDuration(duration) animationType = string.upper(animationType) @@ -2824,9 +3197,33 @@ function DF:CreateAnimation(animation, animationType, order, duration, arg1, arg elseif (animationType == "TRANSLATION") then anim:SetOffset(arg1, arg2) + + elseif (animationType == "PATH") then + local newControlPoint = anim:CreateControlPoint() + anim:SetCurveType(arg4 or "SMOOTH") + newControlPoint:SetOffset(arg2, arg3) + newControlPoint:SetOrder(#anim:GetControlPoints()) + + elseif (animationType == "VERTEXCOLOR" or animationType == "COLOR") then + local r1, g1, b1, a1 = arg1, arg2, arg3, arg4 + local r2, g2, b2, a2 = arg5, arg6, arg7, arg8 + + if ((type(r1) == "table" or type(r1) == "string") and (type(g1) == "table" or type(g1) == "string")) then + r2, g2, b2, a2 = DF:ParseColors(g1) + r1, g1, b1, a1 = DF:ParseColors(r1) + + elseif ((type(r1) == "table" or type(r1) == "string")) then + r1, g1, b1, a1 = DF:ParseColors(r1) + + elseif ((type(r2) == "table" or type(r2) == "string")) then + r2, g2, b2, a2 = DF:ParseColors(r2) + end + + anim:SetStartColor(CreateColor(r1, g1, b1, a1)) + anim:SetEndColor(CreateColor(r2, g2, b2, a2)) end - animation.NextAnimation = animation.NextAnimation + 1 + animationGroup.NextAnimation = animationGroup.NextAnimation + 1 return anim end @@ -2971,13 +3368,13 @@ frameshake_DoUpdate = function(parent, shakeObject, deltaTime) local newX, newY if (shakeObject.AbsoluteSineX) then --absoluting only the sine wave, passing a negative scale will reverse the absolute direction - newX = shakeObject.Amplitude * abs(math.sin(shakeObject.XSineOffset)) * scaleShake * shakeObject.ScaleX + newX = shakeObject.Amplitude * math.abs(math.sin(shakeObject.XSineOffset)) * scaleShake * shakeObject.ScaleX else newX = shakeObject.Amplitude * math.sin(shakeObject.XSineOffset) * scaleShake * shakeObject.ScaleX end if (shakeObject.AbsoluteSineY) then - newY = shakeObject.Amplitude * abs(math.sin(shakeObject.YSineOffset)) * scaleShake * shakeObject.ScaleY + newY = shakeObject.Amplitude * math.abs(math.sin(shakeObject.YSineOffset)) * scaleShake * shakeObject.ScaleY else newY = shakeObject.Amplitude * math.sin(shakeObject.YSineOffset) * scaleShake * shakeObject.ScaleY end @@ -3070,7 +3467,7 @@ local frameshake_play = function(parent, shakeObject, scaleDirection, scaleAmpli --update the amount of shake running on this frame parent.__frameshakes.enabled = parent.__frameshakes.enabled + 1 - if (not parent:GetScript("OnUpdate")) then + if (parent:HasScript("OnUpdate") and not parent:GetScript("OnUpdate")) then parent:SetScript("OnUpdate", function()end) end end @@ -3104,7 +3501,7 @@ local frameshake_SetConfig = function(parent, shakeObject, duration, amplitude, shakeObject.OriginalDuration = shakeObject.Duration end ----@class frameshake : table +---@class df_frameshake : table ---@field Amplitude number ---@field Frequency number ---@field Duration number @@ -3121,9 +3518,9 @@ end ---@field OriginalFrequency number ---@field OriginalAmplitude number ---@field OriginalDuration number ----@field PlayFrameShake fun(parent:uiobject, shakeObject:frameshake, scaleDirection:number?, scaleAmplitude:number?, scaleFrequency:number?, scaleDuration:number?) ----@field StopFrameShake fun(parent:uiobject, shakeObject:frameshake) ----@field SetFrameShakeSettings fun(parent:uiobject, shakeObject:frameshake, duration:number?, amplitude:number?, frequency:number?, absoluteSineX:boolean?, absoluteSineY:boolean?, scaleX:number?, scaleY:number?, fadeInTime:number?, fadeOutTime:number?) +---@field PlayFrameShake fun(parent:uiobject, shakeObject:df_frameshake, scaleDirection:number?, scaleAmplitude:number?, scaleFrequency:number?, scaleDuration:number?) +---@field StopFrameShake fun(parent:uiobject, shakeObject:df_frameshake) +---@field SetFrameShakeSettings fun(parent:uiobject, shakeObject:df_frameshake, duration:number?, amplitude:number?, frequency:number?, absoluteSineX:boolean?, absoluteSineY:boolean?, scaleX:number?, scaleY:number?, fadeInTime:number?, fadeOutTime:number?) ---create a frame shake object ---@param parent uiobject @@ -3137,7 +3534,7 @@ end ---@param fadeInTime number? ---@param fadeOutTime number? ---@param anchorPoints table? ----@return frameshake +---@return df_frameshake function DF:CreateFrameShake(parent, duration, amplitude, frequency, absoluteSineX, absoluteSineY, scaleX, scaleY, fadeInTime, fadeOutTime, anchorPoints) --create the shake table local frameShake = { @@ -3182,7 +3579,7 @@ function DF:CreateFrameShake(parent, duration, amplitude, frequency, absoluteSin FrameshakeUpdateFrame.RegisterFrame (parent) end - tinsert(parent.__frameshakes, frameShake) + table.insert(parent.__frameshakes, frameShake) return frameShake end @@ -3259,23 +3656,29 @@ local glow_overlay_setcolor = function(self, antsColor, glowColor) end local glow_overlay_onshow = function(self) - glow_overlay_play (self) + glow_overlay_play(self) end local glow_overlay_onhide = function(self) - glow_overlay_stop (self) + glow_overlay_stop(self) end ---this is most copied from the wow client code, few changes applied to customize it -function DF:CreateGlowOverlay (parent, antsColor, glowColor) - local pName = parent:GetName() - local fName = pName and (pName.."Glow2") or "OverlayActionGlow" .. math.random(1, 10000000) - if fName and string.len(fName) > 50 then -- shorten to work around too long names - fName = strsub(fName, string.len(fName)-49) +---create a glow overlay around a frame, return a frame and also add parent.overlay to the parent frame +---@param self table +---@param parent frame +---@param antsColor any +---@param glowColor any +function DF:CreateGlowOverlay(parent, antsColor, glowColor) + local parentName = parent:GetName() + local frameName = parentName and (parentName .. "Glow2") or "OverlayActionGlow" .. math.random(1, 10000000) + + if (frameName and string.len(frameName) > 50) then --shorten to work around too long names + frameName = string.sub(frameName, string.len(frameName)-49) end - local glowFrame = CreateFrame("frame", fName, parent, "ActionBarButtonSpellActivationAlert") - glowFrame:HookScript ("OnShow", glow_overlay_onshow) - glowFrame:HookScript ("OnHide", glow_overlay_onhide) + + local glowFrame = CreateFrame("frame", frameName, parent, "ActionBarButtonSpellActivationAlert") + glowFrame:HookScript("OnShow", glow_overlay_onshow) + glowFrame:HookScript("OnHide", glow_overlay_onhide) glowFrame.Play = glow_overlay_play glowFrame.Stop = glow_overlay_stop @@ -3290,23 +3693,24 @@ function DF:CreateGlowOverlay (parent, antsColor, glowColor) local scale = 1.4 - --Make the height/width available before the next frame: - parent.overlay:SetSize(frameWidth * scale, frameHeight * scale) - parent.overlay:SetPoint("TOPLEFT", parent, "TOPLEFT", -frameWidth * 0.32, frameHeight * 0.36) - parent.overlay:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", frameWidth * 0.32, -frameHeight * 0.36) + --make the height/width available before the next frame: + glowFrame:SetSize(frameWidth * scale, frameHeight * scale) + glowFrame:SetPoint("topleft", parent, "topleft", -frameWidth * 0.32, frameHeight * 0.36) + glowFrame:SetPoint("bottomright", parent, "bottomright", frameWidth * 0.32, -frameHeight * 0.36) if (glowFrame.outerGlow) then glowFrame.outerGlow:SetScale(1.2) end + if (glowFrame.ProcStartFlipbook) then glowFrame.ProcStartAnim:Stop() glowFrame.ProcStartFlipbook:ClearAllPoints() - --glowFrame.ProcStartFlipbook:SetAllPoints() - --glowFrame.ProcStartFlipbook:SetSize(frameWidth * scale, frameHeight * scale) glowFrame.ProcStartFlipbook:SetPoint("TOPLEFT", glowFrame, "TOPLEFT", -frameWidth * scale, frameHeight * scale) glowFrame.ProcStartFlipbook:SetPoint("BOTTOMRIGHT", glowFrame, "BOTTOMRIGHT", frameWidth * scale, -frameHeight * scale) end + glowFrame:EnableMouse(false) + return glowFrame end @@ -3322,32 +3726,41 @@ local ants_set_texture_offset = function(self, leftOffset, rightOffset, topOffse self:SetPoint("bottomright", rightOffset, bottomOffset) end -function DF:CreateAnts (parent, antTable, leftOffset, rightOffset, topOffset, bottomOffset, antTexture) + +---create an "ant" animation around the frame, the name "ant" comes from the animation looking like small bright dots moving around the frame +---@param parent frame +---@param antTable df_anttable +---@param leftOffset number? +---@param rightOffset number? +---@param topOffset number? +---@param bottomOffset number? +---@return frame +function DF:CreateAnts(parent, antTable, leftOffset, rightOffset, topOffset, bottomOffset) leftOffset = leftOffset or 0 rightOffset = rightOffset or 0 topOffset = topOffset or 0 bottomOffset = bottomOffset or 0 - local f = CreateFrame("frame", nil, parent) - f:SetPoint("topleft", leftOffset, topOffset) - f:SetPoint("bottomright", rightOffset, bottomOffset) + local antsFrame = CreateFrame("frame", nil, parent) + antsFrame:SetPoint("topleft", leftOffset, topOffset) + antsFrame:SetPoint("bottomright", rightOffset, bottomOffset) - f.SetOffset = ants_set_texture_offset + antsFrame.SetOffset = ants_set_texture_offset - local t = f:CreateTexture(nil, "overlay") - t:SetAllPoints() - t:SetTexture(antTable.Texture) - t:SetBlendMode(antTable.BlendMode or "ADD") - t:SetVertexColor(DF:ParseColors(antTable.Color or "white")) - f.Texture = t + local texture = antsFrame:CreateTexture(nil, "overlay") + texture:SetAllPoints() + texture:SetTexture(antTable.Texture) + texture:SetBlendMode(antTable.BlendMode or "ADD") + texture:SetVertexColor(DF:ParseColors(antTable.Color or "white")) + antsFrame.Texture = texture - f.AntTable = antTable + antsFrame.AntTable = antTable - f:SetScript("OnUpdate", function(self, deltaTime) - AnimateTexCoords (t, self.AntTable.TextureWidth, self.AntTable.TextureHeight, self.AntTable.TexturePartsWidth, self.AntTable.TexturePartsHeight, self.AntTable.AmountParts, deltaTime, self.AntTable.Throttle or 0.025) + antsFrame:SetScript("OnUpdate", function(self, deltaTime) + AnimateTexCoords(texture, self.AntTable.TextureWidth, self.AntTable.TextureHeight, self.AntTable.TexturePartsWidth, self.AntTable.TexturePartsHeight, self.AntTable.AmountParts, deltaTime, self.AntTable.Throttle or 0.025) end) - return f + return antsFrame end --[=[ --test ants @@ -3393,18 +3806,25 @@ end local SetLayerVisibility = function(self, layer1Shown, layer2Shown, layer3Shown) for _, texture in ipairs(self.Borders.Layer1) do - texture:SetShown (layer1Shown) + texture:SetShown(layer1Shown) end for _, texture in ipairs(self.Borders.Layer2) do - texture:SetShown (layer2Shown) + texture:SetShown(layer2Shown) end for _, texture in ipairs(self.Borders.Layer3) do - texture:SetShown (layer3Shown) + texture:SetShown(layer3Shown) end end +---create a border using three textures for each side of the frame, each texture has a different transparency creating a smooth gradient effect +---the parent frame receives three new methods: SetBorderAlpha(a1, a2, a3), SetBorderColor(r, g, b), SetLayerVisibility(layer1Shown, layer2Shown, layer3Shown) +---@param self table +---@param parent frame +---@param alpha1 number? +---@param alpha2 number? +---@param alpha3 number? function DF:CreateBorder(parent, alpha1, alpha2, alpha3) parent.Borders = { Layer1 = {}, @@ -3419,73 +3839,89 @@ function DF:CreateBorder(parent, alpha1, alpha2, alpha3) parent.SetBorderColor = SetBorderColor parent.SetLayerVisibility = SetLayerVisibility - local border1 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border1, "topleft", parent, "topleft", -1, 1) - PixelUtil.SetPoint(border1, "bottomleft", parent, "bottomleft", -1, -1) - border1:SetColorTexture(0, 0, 0, alpha1 or default_border_color1) - local border2 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border2, "topleft", parent, "topleft", -2, 2) - PixelUtil.SetPoint(border2, "bottomleft", parent, "bottomleft", -2, -2) - border2:SetColorTexture(0, 0, 0, alpha2 or default_border_color2) - local border3 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border3, "topleft", parent, "topleft", -3, 3) - PixelUtil.SetPoint(border3, "bottomleft", parent, "bottomleft", -3, -3) - border3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) + do + local leftBorder1 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(leftBorder1, "topleft", parent, "topleft", -1, 1) + PixelUtil.SetPoint(leftBorder1, "bottomleft", parent, "bottomleft", -1, -1) + leftBorder1:SetColorTexture(0, 0, 0, alpha1 or default_border_color1) - tinsert(parent.Borders.Layer1, border1) - tinsert(parent.Borders.Layer2, border2) - tinsert(parent.Borders.Layer3, border3) + local leftBorder2 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(leftBorder2, "topleft", parent, "topleft", -2, 2) + PixelUtil.SetPoint(leftBorder2, "bottomleft", parent, "bottomleft", -2, -2) + leftBorder2:SetColorTexture(0, 0, 0, alpha2 or default_border_color2) - local border1 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border1, "topleft", parent, "topleft", 0, 1) - PixelUtil.SetPoint(border1, "topright", parent, "topright", 1, 1) - border1:SetColorTexture(0, 0, 0, alpha1 or default_border_color1) - local border2 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border2, "topleft", parent, "topleft", -1, 2) - PixelUtil.SetPoint(border2, "topright", parent, "topright", 2, 2) - border2:SetColorTexture(0, 0, 0, alpha2 or default_border_color2) - local border3 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border3, "topleft", parent, "topleft", -2, 3) - PixelUtil.SetPoint(border3, "topright", parent, "topright", 3, 3) - border3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) + local leftBorder3 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(leftBorder3, "topleft", parent, "topleft", -3, 3) + PixelUtil.SetPoint(leftBorder3, "bottomleft", parent, "bottomleft", -3, -3) + leftBorder3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) - tinsert(parent.Borders.Layer1, border1) - tinsert(parent.Borders.Layer2, border2) - tinsert(parent.Borders.Layer3, border3) + table.insert(parent.Borders.Layer1, leftBorder1) + table.insert(parent.Borders.Layer2, leftBorder2) + table.insert(parent.Borders.Layer3, leftBorder3) + end - local border1 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border1, "topright", parent, "topright", 1, 0) - PixelUtil.SetPoint(border1, "bottomright", parent, "bottomright", 1, -1) - border1:SetColorTexture(0, 0, 0, alpha1 or default_border_color1) - local border2 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border2, "topright", parent, "topright", 2, 1) - PixelUtil.SetPoint(border2, "bottomright", parent, "bottomright", 2, -2) - border2:SetColorTexture(0, 0, 0, alpha2 or default_border_color2) - local border3 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border3, "topright", parent, "topright", 3, 2) - PixelUtil.SetPoint(border3, "bottomright", parent, "bottomright", 3, -3) - border3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) + do + local topBorder1 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(topBorder1, "topleft", parent, "topleft", 0, 1) + PixelUtil.SetPoint(topBorder1, "topright", parent, "topright", 1, 1) + topBorder1:SetColorTexture(0, 0, 0, alpha1 or default_border_color1) - tinsert(parent.Borders.Layer1, border1) - tinsert(parent.Borders.Layer2, border2) - tinsert(parent.Borders.Layer3, border3) + local topBorder2 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(topBorder2, "topleft", parent, "topleft", -1, 2) + PixelUtil.SetPoint(topBorder2, "topright", parent, "topright", 2, 2) + topBorder2:SetColorTexture(0, 0, 0, alpha2 or default_border_color2) - local border1 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border1, "bottomleft", parent, "bottomleft", 0, -1) - PixelUtil.SetPoint(border1, "bottomright", parent, "bottomright", 0, -1) - border1:SetColorTexture(0, 0, 0, alpha1 or default_border_color1) - local border2 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border2, "bottomleft", parent, "bottomleft", -1, -2) - PixelUtil.SetPoint(border2, "bottomright", parent, "bottomright", 1, -2) - border2:SetColorTexture(0, 0, 0, alpha2 or default_border_color2) - local border3 = parent:CreateTexture(nil, "background") - PixelUtil.SetPoint(border3, "bottomleft", parent, "bottomleft", -2, -3) - PixelUtil.SetPoint(border3, "bottomright", parent, "bottomright", 2, -3) - border3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) + local topBorder3 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(topBorder3, "topleft", parent, "topleft", -2, 3) + PixelUtil.SetPoint(topBorder3, "topright", parent, "topright", 3, 3) + topBorder3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) + + table.insert(parent.Borders.Layer1, topBorder1) + table.insert(parent.Borders.Layer2, topBorder2) + table.insert(parent.Borders.Layer3, topBorder3) + end + + do + local rightBorder1 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(rightBorder1, "topright", parent, "topright", 1, 0) + PixelUtil.SetPoint(rightBorder1, "bottomright", parent, "bottomright", 1, -1) + rightBorder1:SetColorTexture(0, 0, 0, alpha1 or default_border_color1) + + local rightBorder2 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(rightBorder2, "topright", parent, "topright", 2, 1) + PixelUtil.SetPoint(rightBorder2, "bottomright", parent, "bottomright", 2, -2) + rightBorder2:SetColorTexture(0, 0, 0, alpha2 or default_border_color2) + + local rightBorder3 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(rightBorder3, "topright", parent, "topright", 3, 2) + PixelUtil.SetPoint(rightBorder3, "bottomright", parent, "bottomright", 3, -3) + rightBorder3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) + + table.insert(parent.Borders.Layer1, rightBorder1) + table.insert(parent.Borders.Layer2, rightBorder2) + table.insert(parent.Borders.Layer3, rightBorder3) + end + + do + local bottomBorder1 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(bottomBorder1, "bottomleft", parent, "bottomleft", 0, -1) + PixelUtil.SetPoint(bottomBorder1, "bottomright", parent, "bottomright", 0, -1) + bottomBorder1:SetColorTexture(0, 0, 0, alpha1 or default_border_color1) + + local bottomBorder2 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(bottomBorder2, "bottomleft", parent, "bottomleft", -1, -2) + PixelUtil.SetPoint(bottomBorder2, "bottomright", parent, "bottomright", 1, -2) + bottomBorder2:SetColorTexture(0, 0, 0, alpha2 or default_border_color2) + + local bottomBorder3 = parent:CreateTexture(nil, "background") + PixelUtil.SetPoint(bottomBorder3, "bottomleft", parent, "bottomleft", -2, -3) + PixelUtil.SetPoint(bottomBorder3, "bottomright", parent, "bottomright", 2, -3) + bottomBorder3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) - tinsert(parent.Borders.Layer1, border1) - tinsert(parent.Borders.Layer2, border2) - tinsert(parent.Borders.Layer3, border3) + table.insert(parent.Borders.Layer1, bottomBorder1) + table.insert(parent.Borders.Layer2, bottomBorder2) + table.insert(parent.Borders.Layer3, bottomBorder3) + end end --DFNamePlateBorder as copy from "NameplateFullBorderTemplate" -> DF:CreateFullBorder (name, parent) @@ -3551,7 +3987,7 @@ function DF:CreateFullBorder (name, parent) left:SetPoint("TOPRIGHT", border, "TOPLEFT", 0, 1.0) left:SetPoint("BOTTOMRIGHT", border, "BOTTOMLEFT", 0, -1.0) border.Left = left - tinsert(border.Textures, left) + table.insert(border.Textures, left) local right = border:CreateTexture("$parentRight", "BACKGROUND", nil, -8) --right:SetDrawLayer("BACKGROUND", -8) @@ -3560,7 +3996,7 @@ function DF:CreateFullBorder (name, parent) right:SetPoint("TOPLEFT", border, "TOPRIGHT", 0, 1.0) right:SetPoint("BOTTOMLEFT", border, "BOTTOMRIGHT", 0, -1.0) border.Right = right - tinsert(border.Textures, right) + table.insert(border.Textures, right) local bottom = border:CreateTexture("$parentBottom", "BACKGROUND", nil, -8) --bottom:SetDrawLayer("BACKGROUND", -8) @@ -3569,7 +4005,7 @@ function DF:CreateFullBorder (name, parent) bottom:SetPoint("TOPLEFT", border, "BOTTOMLEFT", 0, 0) bottom:SetPoint("TOPRIGHT", border, "BOTTOMRIGHT", 0, 0) border.Bottom = bottom - tinsert(border.Textures, bottom) + table.insert(border.Textures, bottom) local top = border:CreateTexture("$parentTop", "BACKGROUND", nil, -8) --top:SetDrawLayer("BACKGROUND", -8) @@ -3578,7 +4014,7 @@ function DF:CreateFullBorder (name, parent) top:SetPoint("BOTTOMLEFT", border, "TOPLEFT", 0, 0) top:SetPoint("BOTTOMRIGHT", border, "TOPRIGHT", 0, 0) border.Top = top - tinsert(border.Textures, top) + table.insert(border.Textures, top) return border end @@ -3624,9 +4060,9 @@ function DF:CreateBorderWithSpread(parent, alpha1, alpha2, alpha3, size, spread) border3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) PixelUtil.SetWidth (border3, size, minPixels) - tinsert(parent.Borders.Layer1, border1) - tinsert(parent.Borders.Layer2, border2) - tinsert(parent.Borders.Layer3, border3) + table.insert(parent.Borders.Layer1, border1) + table.insert(parent.Borders.Layer2, border2) + table.insert(parent.Borders.Layer3, border3) --top local border1 = parent:CreateTexture(nil, "background") @@ -3647,9 +4083,9 @@ function DF:CreateBorderWithSpread(parent, alpha1, alpha2, alpha3, size, spread) border3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) PixelUtil.SetHeight(border3, size, minPixels) - tinsert(parent.Borders.Layer1, border1) - tinsert(parent.Borders.Layer2, border2) - tinsert(parent.Borders.Layer3, border3) + table.insert(parent.Borders.Layer1, border1) + table.insert(parent.Borders.Layer2, border2) + table.insert(parent.Borders.Layer3, border3) --right local border1 = parent:CreateTexture(nil, "background") @@ -3670,9 +4106,9 @@ function DF:CreateBorderWithSpread(parent, alpha1, alpha2, alpha3, size, spread) border3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) PixelUtil.SetWidth (border3, size, minPixels) - tinsert(parent.Borders.Layer1, border1) - tinsert(parent.Borders.Layer2, border2) - tinsert(parent.Borders.Layer3, border3) + table.insert(parent.Borders.Layer1, border1) + table.insert(parent.Borders.Layer2, border2) + table.insert(parent.Borders.Layer3, border3) local border1 = parent:CreateTexture(nil, "background") PixelUtil.SetPoint(border1, "bottomleft", parent, "bottomleft", 0 + spread, -1 + spread) @@ -3692,9 +4128,9 @@ function DF:CreateBorderWithSpread(parent, alpha1, alpha2, alpha3, size, spread) border3:SetColorTexture(0, 0, 0, alpha3 or default_border_color3) PixelUtil.SetHeight(border3, size, minPixels) - tinsert(parent.Borders.Layer1, border1) - tinsert(parent.Borders.Layer2, border2) - tinsert(parent.Borders.Layer3, border3) + table.insert(parent.Borders.Layer1, border1) + table.insert(parent.Borders.Layer2, border2) + table.insert(parent.Borders.Layer3, border3) end @@ -3897,6 +4333,9 @@ local specs_per_class = { } +---return an array table with the spec ids the class can have +---@param engClass string +---@return table function DF:GetClassSpecIDs(engClass) return specs_per_class[engClass] end @@ -3904,8 +4343,54 @@ function DF:GetClassSpecIds(engClass) --naming conventions return DF:GetClassSpecIDs(engClass) end +local getDragonflightTalents = function() + if (not ClassTalentFrame) then + ClassTalentFrame_LoadUI() + end + + if (not DF.TalentExporter) then + local talentExporter = CreateFromMixins(ClassTalentImportExportMixin) + DF.TalentExporter = talentExporter + end + + local exportStream = ExportUtil.MakeExportDataStream() + + local configId = C_ClassTalents.GetActiveConfigID() + if (not configId) then + return "" + end + + local configInfo = C_Traits.GetConfigInfo(configId) + if (not configInfo) then + return "" + end + + local currentSpecID = PlayerUtil.GetCurrentSpecID() + + local treeInfo = C_Traits.GetTreeInfo(configId, configInfo.treeIDs[1]) + local treeHash = C_Traits.GetTreeHash(treeInfo.ID) + local serializationVersion = C_Traits.GetLoadoutSerializationVersion() + + DF.TalentExporter:WriteLoadoutHeader(exportStream, serializationVersion, currentSpecID, treeHash) + DF.TalentExporter:WriteLoadoutContent(exportStream, configId, treeInfo.ID) + + return exportStream:GetExportString() +end + +--/dump DetailsFramework:GetDragonlightTalentString() +function DF:GetDragonlightTalentString() + local runOkay, errorText = pcall(getDragonflightTalents) + if (not runOkay) then + DF:Msg("error 0x4517", errorText) + return "" + else + local talentString = errorText + return talentString + end +end + local dispatch_error = function(context, errortext) - DF:Msg( (context or "") .. " |cFFFF9900error|r: " .. (errortext or "")) + error((context or "") .. (errortext or "")) end --call a function with payload, if the callback doesn't exists, quit silently @@ -3930,23 +4415,8 @@ end ---@param ... any ---@return any function DF:Dispatch(func, ...) - if (type(func) ~= "function") then - return dispatch_error(_, "DetailsFramework:Dispatch(func) expect a function as parameter 1.") - end + assert(type(func) == "function", "DetailsFramework:Dispatch(func) expect a function as parameter 1. Received: " .. type(func) .. " instead.") return select(2, xpcall(func, geterrorhandler(), ...)) - - --[=[ - local dispatchResult = {xpcall(func, geterrorhandler(), ...)} - local okay = dispatchResult[1] - - if (not okay) then - return false - end - - tremove(dispatchResult, 1) - - return unpack(dispatchResult) - --]=] end --[=[ @@ -4095,13 +4565,13 @@ function DF:GetCharacterRaceList() for i = 1, 100 do local raceInfo = C_CreatureInfo.GetRaceInfo(i) if (raceInfo and DF.RaceList [raceInfo.raceID]) then - tinsert(DF.RaceCache, {Name = raceInfo.raceName, FileString = raceInfo.clientFileString, ID = raceInfo.raceID}) + table.insert(DF.RaceCache, {Name = raceInfo.raceName, FileString = raceInfo.clientFileString, ID = raceInfo.raceID}) end if IS_WOW_PROJECT_MAINLINE then local alliedRaceInfo = C_AlliedRaces.GetRaceInfoByID(i) if (alliedRaceInfo and DF.AlliedRaceList [alliedRaceInfo.raceID]) then - tinsert(DF.RaceCache, {Name = alliedRaceInfo.maleName, FileString = alliedRaceInfo.raceFileString, ID = alliedRaceInfo.raceID}) + table.insert(DF.RaceCache, {Name = alliedRaceInfo.maleName, FileString = alliedRaceInfo.raceFileString, ID = alliedRaceInfo.raceID}) end end end @@ -4194,7 +4664,7 @@ function DF:GetCharacterPvPTalents(onlySelected, onlySelectedHash) if (onlySelectedHash) then talentList [talentID] = true else - tinsert(talentList, {Name = talentName, ID = talentID, Texture = texture, IsSelected = true}) + table.insert(talentList, {Name = talentName, ID = talentID, Texture = texture, IsSelected = true}) end end return talentList @@ -4208,7 +4678,7 @@ function DF:GetCharacterPvPTalents(onlySelected, onlySelectedHash) for _, talentID in ipairs(slotInfo.availableTalentIDs) do if (not alreadyAdded [talentID]) then local _, talentName, texture, selected = GetPvpTalentInfoByID (talentID) - tinsert(talentList, {Name = talentName, ID = talentID, Texture = texture, IsSelected = selected}) + table.insert(talentList, {Name = talentName, ID = talentID, Texture = texture, IsSelected = selected}) alreadyAdded [talentID] = true end end @@ -4713,9 +5183,9 @@ end do local get = function(self) - local object = tremove(self.notUse, #self.notUse) + local object = table.remove(self.notUse, #self.notUse) if (object) then - tinsert(self.inUse, object) + table.insert(self.inUse, object) if (self.onAcquire) then DF:QuickDispatch(self.onAcquire, object) end @@ -4724,7 +5194,7 @@ do --need to create the new object local newObject = self.newObjectFunc(self, unpack(self.payload)) if (newObject) then - tinsert(self.inUse, newObject) + table.insert(self.inUse, newObject) if (self.onAcquire) then DF:QuickDispatch(self.onAcquire, newObject) end @@ -4740,8 +5210,8 @@ do local release = function(self, object) for i = #self.inUse, 1, -1 do if (self.inUse[i] == object) then - tremove(self.inUse, i) - tinsert(self.notUse, object) + table.remove(self.inUse, i) + table.insert(self.notUse, object) if (self.onRelease) then DF:QuickDispatch(self.onRelease, object) @@ -4753,8 +5223,8 @@ do local reset = function(self) for i = #self.inUse, 1, -1 do - local object = tremove(self.inUse, i) - tinsert(self.notUse, object) + local object = table.remove(self.inUse, i) + table.insert(self.notUse, object) if (self.onReset) then DF:QuickDispatch(self.onReset, object) @@ -4994,3 +5464,36 @@ function _G.__benchmark(bNotPrintResult) end end +function DF:PreviewTexture(texture, left, right, top, bottom) + if (texture and type(texture) == "table" and texture.GetObjectType and texture:GetObjectType() == "Texture") then + DF:Msg("PreviewTexture: you have passed a texture object (uiobject) instead of the texture atlas, filename or id.") + end + + local preview = DetailsFrameworkTexturePreview or CreateFrame("frame", "DetailsFrameworkTexturePreview", UIParent) + preview:SetSize(200, 200) + preview:SetPoint("center") + preview.texture = DetailsFrameworkTexturePreviewTexture or preview:CreateTexture("DetailsFrameworkTexturePreviewTexture", "artwork") + preview.texture:SetAllPoints() + preview.fontString = DetailsFrameworkTexturePreviewFontString or preview:CreateFontString("DetailsFrameworkTexturePreviewFontString", "artwork", "GameFontNormal") + preview.fontString:SetPoint("center", preview, "center", 0, 0) + + preview.texture:SetTexture("") + preview.fontString:SetText("") + + --check if the texture passed is an atlas + if (type(texture) == "string" and C_Texture.GetAtlasInfo(texture)) then + preview.texture:SetAtlas(texture) + + elseif (type(texture) == "string" and texture:find("|T")) then + preview.fontString:SetText(texture) + + elseif (type(texture) == "table") then + preview.texture:SetTexture(texture.file or texture.filename) + preview.texture:SetTexCoord(texture.leftTexCoord, texture.rightTexCoord, texture.topTexCoord, texture.bottomTexCoord) + else + preview.texture:SetTexture(texture) + preview.texture:SetTexCoord(left or 0, right or 1, top or 0, bottom or 1) + end + + preview:Show() +end diff --git a/libs/DF/icongeneric.lua b/libs/DF/icongeneric.lua index 887de83c..e4d88094 100644 --- a/libs/DF/icongeneric.lua +++ b/libs/DF/icongeneric.lua @@ -14,14 +14,94 @@ end ---@field options table ---@field NextIcon number ---@field IconPool table table which store the icons created for this iconrow ----@field SetAuraWithIconTemplate fun(self:df_icongeneric, aI:aurainfo, iconTemplateTable:table) ----@field ClearIcons fun(self:df_icongeneric, resetBuffs:boolean?, resetDebuffs:boolean?) ----@field AlignAuraIcons fun(self:df_icongeneric) + +---@class df_iconrow_generic_options : table +---@field icon_width number? @The width of the icon. +---@field icon_height number? @The height of the icon. +---@field texcoord table? @The texture coordinates of the icon. +---@field show_text boolean? @Whether to show text on the icon. +---@field text_color table? @The color of the text. +---@field text_size number? @The size of the text. +---@field text_font string? @The font of the text. +---@field text_outline string? @The outline style of the text. +---@field text_anchor df_anchor? @The anchor point of the text. +---@field text_alpha_by_percent boolean? @Whether to change the alpha of the text by the percentage of the cooldown. +---@field desc_text boolean? @Whether to show description text. +---@field desc_text_color table? @The color of the description text. +---@field desc_text_size number? @The size of the description text. +---@field desc_text_font string? @The font of the description text. +---@field desc_text_outline string? @The outline style of the description text. +---@field desc_text_anchor string? @The anchor point of the description text. +---@field desc_text_rel_anchor string? @The relative anchor point of the description text. +---@field desc_text_x_offset number? @The x offset of the description text. +---@field desc_text_y_offset number? @The y offset of the description text. +---@field stack_text boolean? @Whether to show stack text. +---@field stack_text_color table? @The color of the stack text. +---@field stack_text_size number? @The size of the stack text. +---@field stack_text_font string? @The font of the stack text. +---@field stack_text_outline string? @The outline style of the stack text. +---@field stack_text_anchor string? @The anchor point of the stack text. +---@field stack_text_rel_anchor string? @The relative anchor point of the stack text. +---@field stack_text_x_offset number? @The x offset of the stack text. +---@field stack_text_y_offset number? @The y offset of the stack text. +---@field left_padding number? @The distance between the right and left sides. +---@field top_padding number? @The distance between the top and bottom sides. +---@field icon_padding number? @The distance between each icon. +---@field backdrop table? @The backdrop options. +---@field backdrop_color table? @The color of the backdrop. +---@field backdrop_border_color table? @The color of the backdrop border. +---@field anchor table? @The anchor options. +---@field grow_direction number? @The direction in which the icons grow. +---@field center_alignment boolean? @Whether to align the icons in the center. +---@field surpress_blizzard_cd_timer boolean? @Whether to suppress the Blizzard cooldown timer. +---@field surpress_tulla_omni_cc boolean? @Whether to suppress the Tulla OmniCC cooldown count. +---@field on_tick_cooldown_update boolean? @Whether to update cooldowns on every tick. +---@field cooldown_max_brightness number? @The maximum brightness of the cooldown, it is adjusted by the percent. +---@field decimal_timer boolean? @Whether to display the timer in decimal format. +---@field show_cooldown boolean? @Whether to show blizzard cooldown animation. +---@field cooldown_reverse boolean? @Whether to reverse the cooldown animation. +---@field cooldown_swipe_enabled boolean? @Whether to enable the cooldown swipe animation. +---@field cooldown_edge_texture string? @The texture for the cooldown edge. +---@field show_horizontal_swipe boolean? @Whether to show the horizontal swipe animation. +---@field swipe_alpha number? @The alpha value for the swipe animation. +---@field swipe_brightness number? @The brightness value for the swipe animation. +---@field swipe_progressive_color boolean? @Whether to use progressive color for the swipe animation. Start on Green and goes to Red, follows percent amount. +---@field swipe_color table? @When the color isn't progressive, this is the color of the swipe +---@field swipe_color_start number[]? @Whether to use yellow color for the swipe animation. +---@field swipe_color_end number[]? @Whether to use red color for the swipe animation. +---@field remove_on_finish boolean? @Whether to remove the icon when the cooldown finishes. Only usable if the icon has a identifier (from setting specific). +---@field first_icon_use_anchor boolean? @The anchor point for the first ico will use the anchor set in options.anchor. + +---@class df_iconrow_generic : df_iconrow +---@field SetCooldown fun(self:df_iconrow_generic, iconFrame:df_icongeneric) +---@field OnIconTick fun(iconFrame:df_icongeneric) +---@field FormatCooldownTime fun(thisTime:number) +---@field FormatCooldownTimeDecimal fun(formattedTime:number) +---@field GetIconGrowDirection fun(self:df_iconrow_generic):number +---@field OnOptionChanged fun(self:df_iconrow_generic, optionName:string) +---@field CreateIcon fun(self:df_iconrow_generic, iconName:string) +---@field GetIcon fun(self:df_iconrow_generic) +---@field SetStacks fun(self:df_iconrow_generic, iconFrame:df_icongeneric, bIsShown:boolean, stacksAmount:number?) +---@field AddSpecificIcon fun(self:df_iconrow_generic, identifierKey:any, spellId:number, borderColor:table, startTime:number, duration:number, forceTexture:string, descText:string, count:number, debuffType:string, caster:string, canStealOrPurge:boolean, spellName:string, isBuff:boolean, modRate:number, iconSettings:table) +---@field AddSpecificIconWithTemplate fun(self:df_iconrow_generic, iconTemplateTable:table) +---@field IsIconShown fun(self:df_iconrow_generic, identifierKey:any) +---@field SetIcon fun(self:df_iconrow_generic, spellId:number, borderColor:table, startTime:number, duration:number, iconTexture:string, descText:string, count:number, debuffType:string, caster:string, canStealOrPurge:boolean, spellName:string, isBuff:boolean, modRate:number, iconSettings:table, expirationTime:number?) +---@field RemoveSpecificIcon fun(self:df_iconrow_generic, identifierKey:any) +---@field ClearIcons fun(self:df_iconrow_generic, resetBuffs:boolean?, resetDebuffs:boolean?) +---@field AlignAuraIcons fun(self:df_iconrow_generic) +---@field SetAuraWithIconTemplate fun(self:df_iconrow_generic, auraInfo:aurainfo, iconTemplateTable:table) +---@field IconPool table +---@field NextIcon number +---@field AuraCache table +---@field shownAmount number +---@field options table +---@field SetSpecificAuraWithIconTemplate fun(self:df_iconrow_generic, identifierKey:any, auraInfo:aurainfo, iconTemplateTable:table) local unpack = unpack local CreateFrame = CreateFrame local PixelUtil = PixelUtil local GetTime = GetTime +local Clamp = detailsFramework.Math.Clamp local spellIconCache = {} local spellNameCache = {} @@ -38,9 +118,16 @@ local iconFrameOnHideScript = function(self) end end +local checkPointCallback = function(iconFrame) + if (iconFrame.timeRemaining < 3) then + + end + return true +end + detailsFramework.IconGenericMixin = { ---create a new icon frame - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame ---@param iconName string the name of the icon frame ---@return df_icongeneric CreateIcon = function(self, iconName) @@ -55,9 +142,8 @@ detailsFramework.IconGenericMixin = { ---@type texture newIcon.CooldownBrightnessTexture = newIcon:CreateTexture(nil, "artwork", nil, 2) newIcon.CooldownBrightnessTexture:SetBlendMode("ADD") - newIcon.CooldownBrightnessTexture:SetAlpha(1) - PixelUtil.SetPoint(newIcon.CooldownBrightnessTexture, "topleft", newIcon, "topleft", 0, 0) - PixelUtil.SetPoint(newIcon.CooldownBrightnessTexture, "bottomright", newIcon, "bottomright", 0, 0) + PixelUtil.SetPoint(newIcon.CooldownBrightnessTexture, "topleft", newIcon.Texture, "topleft", 0, 0) + PixelUtil.SetPoint(newIcon.CooldownBrightnessTexture, "bottomright", newIcon.Texture, "bottomright", 0, 0) ---@type texture newIcon.Border = newIcon:CreateTexture(nil, "background") @@ -80,10 +166,10 @@ detailsFramework.IconGenericMixin = { --create a overlay texture which will indicate the cooldown time newIcon.CooldownTexture = newIcon:CreateTexture(self:GetName() .. "CooldownTexture", "overlay", nil, 6) - newIcon.CooldownTexture:SetColorTexture(1, 1, 1, 1) + newIcon.CooldownTexture:SetTexture("Interface\\BUTTONS\\GreyscaleRamp64", "CLAMP", "CLAMP", "TRILINEAR") + newIcon.CooldownTexture:SetHeight(2) newIcon.CooldownTexture:SetPoint("bottomleft", newIcon.Texture, "bottomleft", 0, 0) newIcon.CooldownTexture:SetPoint("bottomright", newIcon.Texture, "bottomright", 0, 0) - newIcon.CooldownTexture:SetHeight(1) newIcon.CooldownTexture:Hide() newIcon.CooldownEdge = newIcon:CreateTexture(self:GetName() .. "CooldownEdge", "overlay", nil, 7) @@ -95,11 +181,18 @@ detailsFramework.IconGenericMixin = { newIcon.stacks = 0 newIcon:SetScript("OnHide", iconFrameOnHideScript) + local cooldownFrame = CreateFrame("cooldown", "$parentCooldownFrame", newIcon, "CooldownFrameTemplate, BackdropTemplate") + cooldownFrame:SetAllPoints() + cooldownFrame:EnableMouse(false) + cooldownFrame:SetFrameLevel(newIcon:GetFrameLevel()+1) + cooldownFrame.CountdownText = ({cooldownFrame:GetRegions()})[1] + newIcon.Cooldown = cooldownFrame + return newIcon end, ---get an icon frame from the pool - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame ---@return df_icongeneric GetIcon = function(self) ---@type df_icongeneric @@ -152,7 +245,7 @@ detailsFramework.IconGenericMixin = { end, ---adds only if not existing already in the cache - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame AddSpecificIcon = function(self, identifierKey, spellId, borderColor, startTime, duration, forceTexture, descText, count, debuffType, caster, canStealOrPurge, spellName, isBuff, modRate, iconSettings) if (not identifierKey or identifierKey == "") then return @@ -179,18 +272,32 @@ detailsFramework.IconGenericMixin = { end end, + SetSpecificAuraWithIconTemplate = function(self, identifierKey, auraInfo, iconTemplateTable) + if (not identifierKey or identifierKey == "") then + return + end + + if (not self.AuraCache[identifierKey]) then + ---@type df_icongeneric + local iconFrame = self:SetAuraWithIconTemplate(auraInfo, iconTemplateTable) + iconFrame.identifierKey = identifierKey + self.AuraCache[identifierKey] = true + end + end, + ---set an icon frame with a template - ---@param self df_iconrow the parent frame - ---@param aI aurainfo + ---@param self df_iconrow_generic the parent frame + ---@param auraInfo aurainfo ---@param iconTemplateTable df_icontemplate - SetAuraWithIconTemplate = function(self, aI, iconTemplateTable) - local startTime = aI.expirationTime - aI.duration + SetAuraWithIconTemplate = function(self, auraInfo, iconTemplateTable) + local startTime = auraInfo.expirationTime - auraInfo.duration + ---@type df_icongeneric - self:SetIcon(aI.spellId, nil, startTime, aI.duration, aI.icon, nil, aI.applications, aI.dispelName, aI.sourceUnit, aI.isStealable, aI.name, aI.isHelpful, aI.timeMod, iconTemplateTable, aI.expirationTime) + return self:SetIcon(auraInfo.spellId, nil, startTime, auraInfo.duration, auraInfo.icon, nil, auraInfo.applications, auraInfo.dispelName, auraInfo.sourceUnit, auraInfo.isStealable, auraInfo.name, auraInfo.isHelpful, auraInfo.timeMod, iconTemplateTable, auraInfo.expirationTime) end, ---set an icon frame with a template - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame ---@return df_icongeneric? SetIcon = function(self, spellId, borderColor, startTime, duration, iconTexture, descText, count, debuffType, caster, canStealOrPurge, spellName, isBuff, modRate, iconSettings, expirationTime) local actualSpellName, spellIcon = spellNameCache[spellId], spellIconCache[spellId] @@ -213,6 +320,10 @@ detailsFramework.IconGenericMixin = { end end + if (iconSettings.overrideTexture) then + spellIcon = iconSettings.overrideTexture + end + if (spellIcon) then spellName = spellName or actualSpellName or "unknown_aura" modRate = modRate or 1 @@ -223,8 +334,29 @@ detailsFramework.IconGenericMixin = { iconFrame.expirationTime = expirationTime - local widthFromTexture - local heightFromTexture + local width = iconSettings.width or self.options.icon_width + local height = iconSettings.height or self.options.icon_height or width + + --adjust the width and height by scale + local scale = iconSettings.scale or 1 + width = width * scale + height = height * scale + + PixelUtil.SetSize(iconFrame, width, height) + + --set the texture points to be all points minus one + iconFrame.Texture:ClearAllPoints() + PixelUtil.SetPoint(iconFrame.Texture, "topleft", iconFrame, "topleft", 1, -1) + PixelUtil.SetPoint(iconFrame.Texture, "bottomright", iconFrame, "bottomright", -1, 1) + + iconFrame.textureWidth = math.max(iconFrame.Texture:GetWidth(), width) + iconFrame.textureHeight = math.max(iconFrame.Texture:GetHeight(), height) --for some reason, GetHeight() was returning 0 on the first call + + --cache size + iconFrame.width = width + iconFrame.height = height + + iconFrame:Show() if (iconFrame.Texture.texture ~= spellIcon or (iconSettings.coords and iconSettings.coords ~= iconFrame.currentCoords)) then iconFrame.Texture:SetTexture(spellIcon, "CLAMP", "CLAMP", iconSettings.textureFilter or "LINEAR") --"TRILINEAR" @@ -240,38 +372,13 @@ detailsFramework.IconGenericMixin = { iconFrame.Texture:SetTexCoord(0, 1, 0, 1) end - iconFrame.Texture:ClearAllPoints() - if (iconSettings.points) then + iconFrame.Texture:ClearAllPoints() for i = 1, #iconSettings.points do local point = iconSettings.points[i] iconFrame.Texture:SetPoint(point[1], iconFrame, point[2], point[3], point[4]) end - - if (iconSettings.width) then - iconFrame.Texture:SetWidth(iconSettings.width) - widthFromTexture = iconSettings.width - else - iconFrame.Texture:SetWidth(self.options.icon_width) - end - - if (iconSettings.height or iconSettings.width) then - iconFrame.Texture:SetHeight(iconSettings.height or iconSettings.width) - heightFromTexture = iconSettings.height or iconSettings.width - else - iconFrame.Texture:SetHeight(self.options.icon_height) - end - else - if (iconSettings.width) then - iconFrame.Texture:SetWidth(iconSettings.width) - iconFrame.Texture:SetHeight(iconSettings.height or iconSettings.width) - widthFromTexture = iconSettings.width - heightFromTexture = iconSettings.height or iconSettings.width - PixelUtil.SetPoint(iconFrame.Texture, "center", iconFrame, "center", 0, 0) - else - PixelUtil.SetPoint(iconFrame.Texture, "topleft", iconFrame, "topleft", 1, -1) - PixelUtil.SetPoint(iconFrame.Texture, "bottomright", iconFrame, "bottomright", -1, 1) - end + iconFrame.Texture:SetSize(width, height) end iconFrame.Texture.texture = spellIcon @@ -285,6 +392,17 @@ detailsFramework.IconGenericMixin = { end end + iconFrame:SetIgnoreParentAlpha(false) + + if (iconSettings.color) then + local r, g, b, a = detailsFramework:ParseColors(iconSettings.color) + iconFrame.Texture:SetVertexColor(r, g, b, a) + --ignore the param alpha has the settings might have an alpha for it + iconFrame:SetIgnoreParentAlpha(true) + else + iconFrame.Texture:SetVertexColor(1, 1, 1, 1) + end + if (borderColor) then iconFrame.Border:Show() iconFrame.Border:SetVertexColor(unpack(borderColor)) @@ -306,44 +424,33 @@ detailsFramework.IconGenericMixin = { iconFrame.stacks = count or 0 - if (iconSettings.scale) then - iconFrame.Texture:SetScale(iconSettings.scale) - if (widthFromTexture) then - widthFromTexture = widthFromTexture * iconSettings.scale - end - if (heightFromTexture) then - heightFromTexture = heightFromTexture * iconSettings.scale - end - else - iconFrame.Texture:SetScale(1) - end - if (iconSettings.alpha) then iconFrame.Texture:SetAlpha(iconSettings.alpha) else iconFrame.Texture:SetAlpha(1) end - iconFrame:Show() - iconFrame.textureWidth = iconFrame.Texture:GetWidth() - iconFrame.textureHeight = iconFrame.Texture:GetHeight() - PixelUtil.SetSize(iconFrame, iconFrame.textureWidth, iconFrame.textureHeight) - - --cache size - iconFrame.width = iconFrame.textureWidth - iconFrame.height = iconFrame.textureHeight - --iconFrame.Texture:SetBlendMode("ADD") iconFrame.CooldownBrightnessTexture:SetTexture(iconFrame.Texture:GetTexture()) do local left, top, c, bottom, right = iconFrame.Texture:GetTexCoord() iconFrame.CooldownBrightnessTexture:SetTexCoord(left, right, top, bottom) - iconFrame.CooldownBrightnessTexture.cords = {left, right, top, bottom} + + local coords = iconFrame.CooldownBrightnessTexture.cords + if (coords) then + coords[1] = left + coords[2] = right + coords[3] = top + coords[4] = bottom + else + iconFrame.CooldownBrightnessTexture.cords = {left, right, top, bottom} + end + iconFrame.CooldownBrightnessTexture.top = top iconFrame.CooldownBrightnessTexture.bottom = bottom - end - PixelUtil.SetPoint(iconFrame.CooldownBrightnessTexture, "bottomright", iconFrame, "bottomright", -1, 1) + PixelUtil.SetPoint(iconFrame.CooldownBrightnessTexture, "bottomright", iconFrame.Texture, "bottomright", 0, 0) + end --make information available iconFrame.spellId = spellId @@ -388,7 +495,7 @@ detailsFramework.IconGenericMixin = { end end, - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame ---@param iconFrame df_icongeneric SetCooldown = function(self, iconFrame) if (iconFrame.cooldownLooper) then @@ -399,69 +506,166 @@ detailsFramework.IconGenericMixin = { --iconFrame:SetScale(3) --debug - iconFrame.CooldownEdge:Hide() - iconFrame.CooldownEdge.texture = nil + if (options.show_horizontal_swipe) then + iconFrame.CooldownEdge:Show() + iconFrame.CooldownTexture:Show() + iconFrame.CooldownBrightnessTexture:Show() - detailsFramework:SetFontColor(iconFrame.CountdownText, self.options.text_color) + iconFrame.CooldownEdge.texture = nil + iconFrame.CooldownEdge:SetAlpha(0.834) - PixelUtil.SetSize(iconFrame.CooldownEdge, iconFrame.CooldownTexture:GetWidth(), 2) - PixelUtil.SetPoint(iconFrame.CooldownEdge, "topleft", iconFrame.CooldownTexture, "topleft", 0, 0) - PixelUtil.SetPoint(iconFrame.CooldownEdge, "topright", iconFrame.CooldownTexture, "topright", 0, 0) - PixelUtil.SetHeight(iconFrame.CooldownEdge, 2) + PixelUtil.SetSize(iconFrame.CooldownEdge, iconFrame.CooldownTexture:GetWidth(), 2) + PixelUtil.SetPoint(iconFrame.CooldownEdge, "topleft", iconFrame.CooldownTexture, "topleft", 0, 0) + PixelUtil.SetPoint(iconFrame.CooldownEdge, "topright", iconFrame.CooldownTexture, "topright", 0, 0) + PixelUtil.SetHeight(iconFrame.CooldownEdge, 8) - local swipe_brightness = options.swipe_brightness - iconFrame.CooldownBrightnessTexture:SetAlpha(swipe_brightness) + iconFrame.CooldownEdge:SetTexture(options.swipe_white, "CLAMP", "CLAMP", "TRILINEAR") + iconFrame.CooldownEdge.texture = options.swipe_white - local swipe_darkness = options.swipe_alpha - iconFrame.CooldownTexture:SetAlpha(swipe_darkness) - iconFrame.CooldownTexture:SetVertexColor(unpack(options.swipe_color)) + local swipe_brightness = options.swipe_brightness + iconFrame.CooldownBrightnessTexture:SetAlpha(swipe_brightness) + + local swipe_darkness = options.swipe_alpha + iconFrame.CooldownTexture:SetAlpha(swipe_darkness) + iconFrame.CooldownTexture:SetVertexColor(unpack(options.swipe_color)) + else + iconFrame.CooldownEdge:Hide() + iconFrame.CooldownBrightnessTexture:Hide() + iconFrame.CooldownTexture:Hide() + end + + if (options.show_text) then + detailsFramework:SetFontColor(iconFrame.CountdownText, self.options.text_color) + detailsFramework:SetFontSize(iconFrame.CountdownText, self.options.text_size) + detailsFramework:SetFontFace(iconFrame.CountdownText, self.options.text_font) + detailsFramework:SetFontOutline(iconFrame.CountdownText, self.options.text_outline) + detailsFramework:SetAnchor(iconFrame.CountdownText, self.options.text_anchor, iconFrame) + iconFrame.CountdownText:Show() + iconFrame.CountdownText:SetAlpha(1) + else + iconFrame.CountdownText:Hide() + end + + if (options.show_cooldown) then + iconFrame.Cooldown:Show() + iconFrame.Cooldown:SetReverse(options.cooldown_reverse) + iconFrame.Cooldown:SetDrawSwipe(options.cooldown_swipe_enabled) + iconFrame.Cooldown:SetEdgeTexture(options.cooldown_edge_texture) --the yellow edge that follows the cooldown animation + iconFrame.Cooldown:SetHideCountdownNumbers(options.surpress_blizzard_cd_timer) + + iconFrame.Cooldown:SetSwipeTexture([[Interface\Masks\SquareMask]], 0, 0, 0, 0.3) + --iconFrame.Cooldown:SetSwipeColor(1, 1, 1, 1) + --iconFrame.Cooldown:SetSwipeColor(0, 0, 0, 0.1) + + --iconFrame.Cooldown:SetDrawEdge(true) --the same shit as above + --iconFrame.Cooldown:SetDrawSwipe(true) + --iconFrame.Cooldown:SetDrawBling(true) --edge of the animation, a thin horizontal texture + --iconFrame.Cooldown:SetEdgeScale(4) --edge of the animation, a thin horizontal texture + + if (not options.surpress_blizzard_cd_timer) then + detailsFramework:SetFontColor(iconFrame.Cooldown.CountdownText, self.options.text_color) + detailsFramework:SetFontSize(iconFrame.Cooldown.CountdownText, self.options.text_size) + detailsFramework:SetFontFace(iconFrame.Cooldown.CountdownText, self.options.text_font) + detailsFramework:SetFontOutline(iconFrame.Cooldown.CountdownText, self.options.text_outline) + end + iconFrame.Cooldown.noCooldownCount = options.surpress_tulla_omni_cc - iconFrame.CooldownEdge:SetAlpha(0.834) + CooldownFrame_Set(iconFrame.Cooldown, iconFrame.startTime, iconFrame.duration, true, true, iconFrame.modRate) + + iconFrame.CooldownBrightnessTexture:Show() + else + iconFrame.Cooldown:Hide() + end self.OnIconTick(iconFrame) - local amountOfLoops = math.floor(iconFrame.duration / 0.5) + local amountOfLoops = math.floor(iconFrame.duration / 0.25) local loopEndCallback = nil - local checkPointCallback = nil - - local newLooper = detailsFramework.Schedules.NewLooper(0.5, self.OnIconTick, amountOfLoops, loopEndCallback, checkPointCallback, iconFrame) - iconFrame.cooldownLooper = newLooper + if (iconFrame.options.remove_on_finish) then + --increase the amount of loops in one, so the last loop will remove the icon + --otherwise it might finish + amountOfLoops = amountOfLoops + 1 + local newLooper = detailsFramework.Schedules.NewLooper(0.25, self.OnIconTick, amountOfLoops, loopEndCallback, checkPointCallback, iconFrame) + iconFrame.cooldownLooper = newLooper + else + local newLooper = detailsFramework.Schedules.NewLooper(0.25, self.OnIconTick, amountOfLoops, loopEndCallback, checkPointCallback, iconFrame) + iconFrame.cooldownLooper = newLooper + end end, ---@param iconFrame df_icongeneric OnIconTick = function(iconFrame) local now = GetTime() --local percent = (now - iconFrame.startTime) / iconFrame.duration --no mod rate - local percent = ((now - iconFrame.startTime) / (iconFrame.modRate or 1)) / (iconFrame.duration / (iconFrame.modRate or 1)) + local percent = (((now - iconFrame.startTime) / (iconFrame.modRate or 1)) / (iconFrame.duration / (iconFrame.modRate or 1))) or 0 local options = iconFrame.options + percent = Saturate(percent) --percent = abs(percent - 1) - local newHeight = math.min(iconFrame.textureHeight * percent, iconFrame.textureHeight) - iconFrame.CooldownTexture:SetHeight(newHeight) + iconFrame.timeRemaining = iconFrame.duration - (now - iconFrame.startTime) - PixelUtil.SetPoint(iconFrame.CooldownBrightnessTexture, "bottomright", iconFrame, "bottomright", 0, newHeight) --iconFrame.textureHeight - - local left, right, top, bottom = unpack(iconFrame.CooldownBrightnessTexture.cords) - local newBottomCord = Lerp(iconFrame.CooldownBrightnessTexture.top, iconFrame.CooldownBrightnessTexture.bottom, abs(percent - 1)) - iconFrame.CooldownBrightnessTexture:SetTexCoord(left, right, top, newBottomCord) + if (percent >= 1) then + --time expired + if (options.remove_on_finish) then + iconFrame:GetParent():RemoveSpecificIcon(iconFrame.identifierKey) + return + else + percent = 1 + end + end - if (percent > options.swipe_percent2) then - if (options.swipe_red and iconFrame.CooldownEdge.texture ~= options.swipe_red) then - iconFrame.CooldownEdge:Show() - iconFrame.CooldownEdge:SetTexture(options.swipe_red) - iconFrame.CooldownEdge.texture = options.swipe_red + if (options.show_horizontal_swipe) then + local newHeight = math.min(iconFrame.textureHeight * percent, iconFrame.textureHeight) + iconFrame.CooldownTexture:SetHeight(newHeight) + + PixelUtil.SetPoint(iconFrame.CooldownBrightnessTexture, "bottomright", iconFrame.Texture, "bottomright", 0, newHeight) --iconFrame.textureHeight - + local left, right, top, bottom = unpack(iconFrame.CooldownBrightnessTexture.cords) + local newBottomCord = Lerp(iconFrame.CooldownBrightnessTexture.top, iconFrame.CooldownBrightnessTexture.bottom, abs(percent - 1)) + iconFrame.CooldownBrightnessTexture:SetTexCoord(left, right, top, newBottomCord) + + --local newBrightness = Lerp(Saturate(options.cooldown_max_brightness-0.6), options.cooldown_max_brightness, percent) + --iconFrame.CooldownBrightnessTexture:SetAlpha(newBrightness) + + if (options.swipe_progressive_color) then + --interpolate from green to red + --percent goes from 0 to 1, where zero is the start of the cooldown and 1 is the end + if (options.swipe_color_start and options.swipe_color_end) then + --use the first and second color + local r1, g1, b1 = unpack(options.swipe_color_start) + local r2, g2, b2 = unpack(options.swipe_color_end) + local r, g, b = detailsFramework.Math.LerpLinearColor(percent, 1, r1, g1, b1, r2, g2, b2) + iconFrame.CooldownEdge:SetVertexColor(r, g, b, 0.834) + else + --use a solid color + iconFrame.CooldownEdge:SetVertexColor(unpack(options.swipe_color)) + end + + --iconFrame.CooldownEdge:SetVertexColor(percent, math.abs(percent-1), 0, 0.834) + local alpha = Saturate(0.2 + percent) + iconFrame.CooldownEdge:SetAlpha(alpha) + else + --use a solid color + iconFrame.CooldownEdge:SetVertexColor(unpack(options.swipe_color)) end + end - elseif (percent > options.swipe_percent1) then - if (options.swipe_yellow and iconFrame.CooldownEdge.texture ~= options.swipe_yellow) then - iconFrame.CooldownEdge:Show() - iconFrame.CooldownEdge:SetTexture(options.swipe_yellow) - iconFrame.CooldownEdge.texture = options.swipe_yellow + if (options.show_cooldown) then + if (options.cooldown_max_brightness) then + iconFrame.CooldownBrightnessTexture:SetAlpha(Lerp(0, options.cooldown_max_brightness, percent)) + local swipeAlpha = Saturate(Lerp(0, 1, percent)) + local exponentialCurve = 0.1 * math.exp(3.5 * swipeAlpha) + exponentialCurve = Saturate(exponentialCurve) + iconFrame.Cooldown:SetSwipeColor(0, 0, 0, exponentialCurve) end end - --iconFrame.CountdownText:SetText(iconFrame.parentIconRow.FormatCooldownTime(iconFrame.duration - (now - iconFrame.startTime))) --no mod rate - iconFrame.CountdownText:SetText(iconFrame.parentIconRow.FormatCooldownTime((iconFrame.duration - (now - iconFrame.startTime)) / (iconFrame.modRate or 1))) - --self.CountdownText:Show() + --show the countdown text + if (options.show_text) then + iconFrame.CountdownText:SetText(iconFrame.parentIconRow.FormatCooldownTime((iconFrame.duration - (now - iconFrame.startTime)) / (iconFrame.modRate or 1))) + if (options.text_alpha_by_percent) then + iconFrame.CountdownText:SetAlpha(percent) + end + end end, FormatCooldownTime = function(thisTime) @@ -495,7 +699,7 @@ detailsFramework.IconGenericMixin = { end end, - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame ---@param identifierKey any RemoveSpecificIcon = function(self, identifierKey) if (not identifierKey or identifierKey == "") then @@ -527,7 +731,7 @@ detailsFramework.IconGenericMixin = { self:AlignAuraIcons() end, - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame ClearIcons = function(self, resetBuffs, resetDebuffs) resetBuffs = resetBuffs ~= false resetDebuffs = resetDebuffs ~= false @@ -560,7 +764,7 @@ detailsFramework.IconGenericMixin = { self:AlignAuraIcons() end, - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame AlignAuraIcons = function(self) local iconPool = self.IconPool local iconAmount = #iconPool @@ -604,22 +808,30 @@ detailsFramework.IconGenericMixin = { if (growDirection == 1) then --grow to right if (bIsFirstIcon) then - local attachSide = (bIsCenterAligned and "center") or (nWhichSide and not detailsFramework.SideIsCorner[nWhichSide] and "left") or "bottomleft" - PixelUtil.SetPoint(iconFrame, attachSide, anchorTo, attachSide, 0, 0) + if (self.options.first_icon_use_anchor) then + detailsFramework:SetAnchor(iconFrame, self.options.anchor, self) + else + local attachSide = (bIsCenterAligned and "center") or (nWhichSide and not detailsFramework.SideIsCorner[nWhichSide] and "left") or "bottomleft" + PixelUtil.SetPoint(iconFrame, attachSide, anchorTo, attachSide, 0, 0) + end else PixelUtil.SetPoint(iconFrame, "left", anchorTo, "right", xPadding, 0) end elseif (growDirection == 2) then --grow to left if (bIsFirstIcon) then - local attachSide = (bIsCenterAligned and "center") or (nWhichSide and not detailsFramework.SideIsCorner[nWhichSide] and "right") or "bottomright" - PixelUtil.SetPoint(iconFrame, attachSide, anchorTo, attachSide, 0, 0) + if (self.options.first_icon_use_anchor) then + detailsFramework:SetAnchor(iconFrame, self.options.anchor, self) + else + local attachSide = (bIsCenterAligned and "center") or (nWhichSide and not detailsFramework.SideIsCorner[nWhichSide] and "right") or "bottomright" + PixelUtil.SetPoint(iconFrame, attachSide, anchorTo, attachSide, 0, 0) + end else PixelUtil.SetPoint(iconFrame, "right", anchorTo, "left", xPadding, 0) end end - width = width + ((iconFrame.width or iconFrame:GetWidth()) * iconFrame:GetScale()) + 1 + width = width + ((iconFrame.width or iconFrame:GetWidth())) + 1 --* iconFrame:GetScale() removed the getscale as now the scale are applied to the width and height end if (bIsCenterAligned) then @@ -636,13 +848,13 @@ detailsFramework.IconGenericMixin = { end end, - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame GetIconGrowDirection = function(self) local side = self.options.anchor.side return detailsFramework.GrowDirectionBySide[side] end, - ---@param self df_iconrow the parent frame + ---@param self df_iconrow_generic the parent frame OnOptionChanged = function(self, optionName) if (self.SetBackdropColor) then self:SetBackdropColor(unpack(self.options.backdrop_color)) @@ -651,19 +863,18 @@ detailsFramework.IconGenericMixin = { end, } -local default_icon_row_options = { +---@type df_iconrow_generic_options +local default_iconrow_generic_options = { icon_width = 20, icon_height = 20, texcoord = {.1, .9, .1, .9}, - show_text = true, + show_text = false, text_color = {1, 1, 1, 1}, text_size = 12, text_font = "Arial Narrow", text_outline = "NONE", - text_anchor = "center", - text_rel_anchor = "center", - text_x_offset = 0, - text_y_offset = 0, + text_anchor = {side = 9, x = 0, y = 0}, + text_alpha_by_percent = false, desc_text = true, desc_text_color = {1, 1, 1, 1}, desc_text_size = 7, @@ -691,29 +902,35 @@ local default_icon_row_options = { anchor = {side = 6, x = 2, y = 0}, grow_direction = 1, --1 = to right 2 = to left center_alignment = false, --if true if will align the icons with grow_direction and then set the iconRow width to match the length used by all icons - surpress_blizzard_cd_timer = false, + + show_cooldown = false, surpress_tulla_omni_cc = false, - on_tick_cooldown_update = true, - decimal_timer = false, + decimal_timer = false, --nop, not in use cooldown_reverse = false, cooldown_swipe_enabled = true, cooldown_edge_texture = "Interface\\Cooldown\\edge", + cooldown_max_brightness = 0.7, + surpress_blizzard_cd_timer = false, + on_tick_cooldown_update = true, --nop, not in use + show_horizontal_swipe = true, + swipe_progressive_color = true, swipe_alpha = 0.5, swipe_brightness = 0.5, - swipe_color = {0, 0, 0}, - swipe_yellow = false, - swipe_red = false, - swipe_percent1 = 0.75, - swipe_percent2 = 0.90, + swipe_color = {0, 0, 0}, --this variable is having conflicts because it's in use by other things + swipe_color_start = {0, 1, 0}, + swipe_color_end = {1, 0, 0}, - --first_icon_anchor = "auto", + remove_on_finish = false, + first_icon_use_anchor = false, } + + ---@param parent frame ---@param name string? ---@param options table? ----@return df_iconrow +---@return df_iconrow_generic function detailsFramework:CreateIconRowGeneric(parent, name, options) local newIconRowFrame = CreateFrame("frame", name, parent, "BackdropTemplate") newIconRowFrame.IconPool = {} @@ -724,7 +941,7 @@ function detailsFramework:CreateIconRowGeneric(parent, name, options) detailsFramework:Mixin(newIconRowFrame, detailsFramework.IconGenericMixin) detailsFramework:Mixin(newIconRowFrame, detailsFramework.OptionsFunctions) - newIconRowFrame:BuildOptionsTable(default_icon_row_options, options) + newIconRowFrame:BuildOptionsTable(default_iconrow_generic_options, options) newIconRowFrame:SetSize(1, 1) diff --git a/libs/DF/label.lua b/libs/DF/label.lua index c86cb2a2..0c04a82a 100644 --- a/libs/DF/label.lua +++ b/libs/DF/label.lua @@ -249,6 +249,8 @@ detailsFramework:Mixin(LabelMetaFunctions, detailsFramework.ScriptHookMixin) --template function LabelMetaFunctions:SetTemplate(template) + template = detailsFramework:ParseTemplate(self.type, template) + if (template.size) then detailsFramework:SetFontSize(self.label, template.size) end @@ -266,7 +268,7 @@ detailsFramework:Mixin(LabelMetaFunctions, detailsFramework.ScriptHookMixin) ------------------------------------------------------------------------------------------------------------ --object constructor ----@class df_label: fontstring +---@class df_label: fontstring, df_widgets ---@field widget fontstring widget and label points to the same fontstring ---@field label fontstring widget and label points to the same fontstring ---@field align justifyh @@ -289,10 +291,19 @@ detailsFramework:Mixin(LabelMetaFunctions, detailsFramework.ScriptHookMixin) ---@field SetTextColor fun(self: df_label, red: any, green: number|nil, blue: number|nil, alpha: number|nil) set the button text color ---@field SetTextTruncated fun(self: df_label, text: string, maxWidth: width) +--there are two calls to create a label: detailsFramework:CreateLabel and detailsFramework:NewLabel +--NewLabel is the original function, CreateLabel is an alias with different parameters order to make it easier to use +--When converting the NewLabel() call with CreateLabel() do this: +--rename NewLabel to CreateLabel; +--change the order of the parameters: parent, container, name, member, text, font, size, color, layer => parent, text, size, color, font, member, name, layer +--container is gone from the parameters pm CreateLabel +--detailsFramework:CreateLabel(parent, text, size, color, font, member, name, layer) +--detailsFramework:NewLabel(parent, container, name, member, text, font, size, color, layer) + ---create a new label object ---@param parent frame ---@param text string|table for used for localization, expects a locTable from the language system ----@param size number|nil +---@param size any? ---@param color any|nil ---@param font string|nil ---@param member string|nil @@ -300,9 +311,19 @@ detailsFramework:Mixin(LabelMetaFunctions, detailsFramework.ScriptHookMixin) ---@param layer drawlayer|nil ---@return df_label|nil function detailsFramework:CreateLabel(parent, text, size, color, font, member, name, layer) - return detailsFramework:NewLabel(parent, nil, name, member, text, font, size, color, layer) + return detailsFramework:NewLabel(parent, parent, name, member, text, font, size, color, layer) end +---create a new label object +---@param parent frame +---@param container frame +---@param name string? +---@param member string? +---@param text string|table regular text or a locTable from the language system +---@param font string? +---@param size any? +---@param color any? +---@param layer drawlayer? function detailsFramework:NewLabel(parent, container, name, member, text, font, size, color, layer) if (not parent) then return error("Details! Framework: parent not found.", 2) @@ -317,11 +338,10 @@ function detailsFramework:NewLabel(parent, container, name, member, text, font, end if (name:find("$parent")) then - local parentName = detailsFramework.GetParentName(parent) + local parentName = detailsFramework:GetParentName(parent) name = name:gsub("$parent", parentName) end - ---@type df_label local labelObject = {type = "label", dframework = true} if (member) then @@ -340,7 +360,8 @@ function detailsFramework:NewLabel(parent, container, name, member, text, font, font = "GameFontNormal" end - labelObject.label = parent:CreateFontString(name, layer or "OVERLAY", font) + labelObject.container = container + labelObject.label = parent:CreateFontString(name, layer or "overlay", font) labelObject.widget = labelObject.label labelObject.label.MyObject = labelObject @@ -363,7 +384,7 @@ function detailsFramework:NewLabel(parent, container, name, member, text, font, if (detailsFramework.Language.IsLocTable(locTable)) then detailsFramework.Language.SetTextWithLocTable(labelObject.widget, locTable) else - labelObject.label:SetText(text) + labelObject.label:SetText("type(text) is a table, but locTable isn't registered.") end else labelObject.label:SetText(text) diff --git a/libs/DF/loadconditions.lua b/libs/DF/loadconditions.lua index 8a717272..c9fe9380 100644 --- a/libs/DF/loadconditions.lua +++ b/libs/DF/loadconditions.lua @@ -151,7 +151,7 @@ function detailsFramework:CreateLoadFilterParser(callback) if (not bFoundItem) then filterFrame.FindBackpackItem:Cancel() xpcall(callback, geterrorhandler(), "RACE_STOP") - return true + return end end) end) diff --git a/libs/DF/math.lua b/libs/DF/math.lua index d77900d6..f387c110 100644 --- a/libs/DF/math.lua +++ b/libs/DF/math.lua @@ -37,6 +37,8 @@ DF.Math = {} ---@field Clamp fun(minValue: number, maxValue: number, value: number) : number dont allow a number ot be lower or bigger than a certain range ---@field Round fun(num: number, numDecimalPlaces: number) : number cut fractions on a float ---@field GetObjectCoordinates fun(object: uiobject) : objectcoordinates return the coordinates of the four corners of an object +---@field MultiplyBy fun(value: number, ...) : ... multiply all the passed values by value. +---@field MapRangeColor fun(inputX: number, inputY: number, outputX: number, outputY: number, red: number, green: number, blue: number) : number, number, number ---find distance between two units @@ -69,6 +71,31 @@ function DF.Math.MapRangeClamped(inputX, inputY, outputX, outputY, value) return DF.Math.GetRangeValue(outputX, outputY, Clamp(DF.Math.GetRangePercent(inputX, inputY, value), 0, 1)) end +---*Receives a color, the range of the color and a range to map the color to, returns the color in the new range +---*Example: MapRangeColor(0, 1, 0, 255, 0.5, 0.5, 0.5) returns 127.5, 127.5, 127.5 +---@param inputX number X range of the original color +---@param inputY number Y range of the original color +---@param outputX number X range of the new color +---@param outputY number Y range of the new color +---@param red number +---@param green number +---@param blue number +---@return number, number, number +function DF.Math.MapRangeColor(inputX, inputY, outputX, outputY, red, green, blue) + local newR = DF.Math.MapRangeClamped(inputX, inputY, outputX, outputY, red) + local newG = DF.Math.MapRangeClamped(inputX, inputY, outputX, outputY, green) + local newB = DF.Math.MapRangeClamped(inputX, inputY, outputX, outputY, blue) + return newR, newG, newB +end + +function DF.Math.MultiplyBy(value, ...) + local values = {} + for i = 1, select("#", ...) do + values[i] = select(i, ...) * value + end + return unpack(values) +end + function DF.Math.MapRangeUnclamped(inputX, inputY, outputX, outputY, value) return DF.Math.GetRangeValue(outputX, outputY, DF.Math.GetRangePercent(inputX, inputY, value)) end diff --git a/libs/DF/normal_bar.lua b/libs/DF/normal_bar.lua index 3ddce3c3..b464e80e 100644 --- a/libs/DF/normal_bar.lua +++ b/libs/DF/normal_bar.lua @@ -761,7 +761,7 @@ function DF:NewBar (parent, container, name, member, w, h, value, texture_name) end if (name:find("$parent")) then - local parentName = DF.GetParentName(parent) + local parentName = DF:GetParentName(parent) name = name:gsub("$parent", parentName) end diff --git a/libs/DF/panel.lua b/libs/DF/panel.lua index b877aa32..7132e2bc 100644 --- a/libs/DF/panel.lua +++ b/libs/DF/panel.lua @@ -1986,11 +1986,11 @@ local SimplePanel_frame_backdrop_border_color = {0, 0, 0, 1} --the slider was anchoring to with_label and here here were anchoring the slider again ---@class df_scalebar : slider ---@field thumb texture -function detailsFramework:CreateScaleBar(frame, config) --~scale +function detailsFramework:CreateScaleBar(frame, config, bNoRightClick) --~scale ---@type df_scalebar local scaleBar, text = detailsFramework:CreateSlider(frame, 120, 14, 0.6, 1.6, 0.1, config.scale, true, "ScaleBar", nil, "Scale:", detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE"), detailsFramework:GetTemplate("font", "ORANGE_FONT_TEMPLATE")) scaleBar.thumb:SetWidth(24) - scaleBar:SetValueStep(0.1) + scaleBar:SetValueStep(0.05) scaleBar:SetObeyStepOnDrag(true) scaleBar.mouseDown = false rawset(scaleBar, "lockdown", true) @@ -2023,26 +2023,32 @@ function detailsFramework:CreateScaleBar(frame, config) --~scale end) editbox:SetScript("OnEscapePressed", function() + if (bNoRightClick) then + return + end editbox:ClearFocus() editbox:Hide() editbox:SetText(editbox.defaultValue) end) scaleBar:SetScript("OnMouseDown", function(_, mouseButton) - if (mouseButton == "RightButton") then + if (mouseButton == "LeftButton" or (mouseButton == "RightButton" and bNoRightClick)) then + scaleBar.mouseDown = true + + elseif (mouseButton == "RightButton") then + if (bNoRightClick) then + return + end editbox:Show() editbox:SetAllPoints() editbox:SetText(config.scale) editbox:SetFocus(true) editbox.defaultValue = config.scale - - elseif (mouseButton == "LeftButton") then - scaleBar.mouseDown = true end end) scaleBar:SetScript("OnMouseUp", function(_, mouseButton) - if (mouseButton == "LeftButton") then + if (mouseButton == "LeftButton" or (mouseButton == "RightButton" and bNoRightClick)) then scaleBar.mouseDown = false frame:SetScale(config.scale) editbox.defaultValue = config.scale @@ -2158,6 +2164,7 @@ function detailsFramework:CreateSimplePanel(parent, width, height, title, frameN local titleBar = CreateFrame("frame", frameName .. "TitleBar", simplePanel, "BackdropTemplate") if (panelOptions.RoundedCorners) then + --a key named "TitleBar" is created by the rounded corners function simplePanel.TitleBar:SetColor(.2, .2, .2, 0.4) simplePanel.TitleBar:SetBorderCornerColor(0, 0, 0, 0) @@ -2169,7 +2176,6 @@ function detailsFramework:CreateSimplePanel(parent, width, height, title, frameN titleBar:SetBackdrop(SimplePanel_frame_backdrop) titleBar:SetBackdropColor(.2, .2, .2, 1) titleBar:SetBackdropBorderColor(0, 0, 0, 1) - simplePanel.TitleBar = titleBar end local close = CreateFrame("button", frameName and frameName .. "CloseButton", titleBar) @@ -3810,6 +3816,7 @@ end ---@field SetData fun(self:df_scrollbox, data:table) ---@field GetData fun(self:df_scrollbox): table ---@field OnSetData fun(self:df_scrollbox, data:table)? if exists, this function is called after the SetData with the same parameters +---@field ScrollBar statusbar ---@field ---create a scrollbox with the methods :Refresh() :SetData() :CreateLine() @@ -4222,9 +4229,18 @@ detailsFramework.RadioGroupCoreFunctions = { end if (optionTable.mask) then - checkbox.Icon:SetMask(optionTable.mask) + if (not checkbox.Icon.Mask) then + checkbox.Icon.Mask = checkbox:CreateMaskTexture(nil, "overlay") + checkbox.Icon.Mask:SetAllPoints(checkbox.Icon.widget) + checkbox.Icon.Mask:SetTexture(optionTable.mask) + checkbox.Icon:AddMaskTexture(checkbox.Icon.Mask) + end + checkbox.Icon.Mask:SetTexture(optionTable.mask) else - checkbox.Icon:SetMask("") + --checkbox.Icon:SetMask("") + if (checkbox.Icon.Mask) then + checkbox.Icon.Mask:SetTexture("") + end end else checkbox.Icon:SetTexture("") @@ -4317,6 +4333,7 @@ detailsFramework.RadioGroupCoreFunctions = { ---@field param any? ---@field texture string? ---@field texcoord table? +---@field mask any? ---@field width number? ---@field height number? ---@field text_size number? diff --git a/libs/DF/picture.lua b/libs/DF/picture.lua index 24915a3a..43ed1a64 100644 --- a/libs/DF/picture.lua +++ b/libs/DF/picture.lua @@ -1,4 +1,5 @@ +---@type detailsframework local detailsFramework = _G["DetailsFramework"] if (not detailsFramework or not DetailsFrameworkCanLoad) then return @@ -226,46 +227,72 @@ detailsFramework:Mixin(ImageMetaFunctions, detailsFramework.ScriptHookMixin) end end - function ImageMetaFunctions:SetGradient(gradientType, fromColor, toColor) + function ImageMetaFunctions:SetGradient(gradientType, fromColor, toColor, bInvert) fromColor = detailsFramework:FormatColor("tablemembers", fromColor) toColor = detailsFramework:FormatColor("tablemembers", toColor) + + if (bInvert) then + local temp = fromColor + fromColor = toColor + toColor = temp + end + self.image:SetGradient(gradientType, fromColor, toColor) end ------------------------------------------------------------------------------------------------------------ --object constructor - ---@class df_image : texture + ---@class df_image : texture, df_widgets ---@field SetGradient fun(gradientType: "vertical"|"horizontal", fromColor: table, toColor: table) + ---@field image texture + + ---@class df_gradienttable : table + ---@field gradient "vertical"|"horizontal" + ---@field fromColor table|string + ---@field toColor table|string + ---@field invert boolean? ---create an object that encapsulates a texture and add additional methods to it + ---this function is an alias of NewImage() with a different name and parameters in different order ---@param parent frame - ---@param texture texturepath|textureid - ---@param width number - ---@param height number - ---@param layer drawlayer - ---@param coords {key1: number, key2: number, key3: number, key4: number} - ---@param member string - ---@param name string - ---@return table|nil + ---@param texture texturepath|textureid|df_gradienttable|nil + ---@param width number? + ---@param height number? + ---@param layer drawlayer? + ---@param coords {key1: number, key2: number, key3: number, key4: number}? + ---@param member string? + ---@param name string? + ---@return df_image function detailsFramework:CreateTexture(parent, texture, width, height, layer, coords, member, name) return detailsFramework:NewImage(parent, texture, width, height, layer, coords, member, name) end ---create an object that encapsulates a texture and add additional methods to it + ---this function is an alias of NewImage() with a different name and parameters in different order ---@param parent frame - ---@param texture texturepath|textureid - ---@param width number - ---@param height number - ---@param layer drawlayer - ---@param coords {key1: number, key2: number, key3: number, key4: number} - ---@param member string - ---@param name string - ---@return table|nil + ---@param texture texturepath|textureid|df_gradienttable|nil + ---@param width number? + ---@param height number? + ---@param layer drawlayer? + ---@param coords {key1: number, key2: number, key3: number, key4: number}? + ---@param member string? + ---@param name string? + ---@return df_image function detailsFramework:CreateImage(parent, texture, width, height, layer, coords, member, name) return detailsFramework:NewImage(parent, texture, width, height, layer, coords, member, name) end + ---create an object that encapsulates a texture and add additional methods to it + ---@param parent frame + ---@param texture texturepath|textureid|df_gradienttable|nil + ---@param width number? + ---@param height number? + ---@param layer drawlayer? + ---@param texCoord {key1: number, key2: number, key3: number, key4: number}? + ---@param member string? + ---@param name string? + ---@return df_image function detailsFramework:NewImage(parent, texture, width, height, layer, texCoord, member, name) if (not parent) then return error("DetailsFrameWork: NewImage() parent not found.", 2) @@ -277,7 +304,7 @@ detailsFramework:Mixin(ImageMetaFunctions, detailsFramework.ScriptHookMixin) end if (name:find("$parent")) then - local parentName = detailsFramework.GetParentName(parent) + local parentName = detailsFramework:GetParentName(parent) name = name:gsub("$parent", parentName) end @@ -313,26 +340,45 @@ detailsFramework:Mixin(ImageMetaFunctions, detailsFramework.ScriptHookMixin) ImageObject.image.MyObject = ImageObject - if (width) then - ImageObject.image:SetWidth(width) - end - if (height) then - ImageObject.image:SetHeight(height) - end - if (texture) then if (type(texture) == "table") then if (texture.gradient) then + ---@type df_gradienttable + local gradientTable = texture + if (detailsFramework.IsDragonflight() or detailsFramework.IsNonRetailWowWithRetailAPI()) then ImageObject.image:SetColorTexture(1, 1, 1, 1) - local fromColor = detailsFramework:FormatColor("tablemembers", texture.fromColor) - local toColor = detailsFramework:FormatColor("tablemembers", texture.toColor) - ImageObject.image:SetGradient(texture.gradient, fromColor, toColor) + local fromColor = detailsFramework:FormatColor("tablemembers", gradientTable.fromColor) + local toColor = detailsFramework:FormatColor("tablemembers", gradientTable.toColor) + + if (gradientTable.invert) then + local temp = fromColor + fromColor = toColor + toColor = temp + end + + ImageObject.image:SetGradient(gradientTable.gradient, fromColor, toColor) else - local fromR, fromG, fromB, fromA = detailsFramework:ParseColors(texture.fromColor) - local toR, toG, toB, toA = detailsFramework:ParseColors(texture.toColor) + local fromR, fromG, fromB, fromA = detailsFramework:ParseColors(gradientTable.fromColor) + local toR, toG, toB, toA = detailsFramework:ParseColors(gradientTable.toColor) + + if (gradientTable.invert) then + local temp = fromR + fromR = toR + toR = temp + temp = fromG + fromG = toG + toG = temp + temp = fromB + fromB = toB + toB = temp + temp = fromA + fromA = toA + toA = temp + end + ImageObject.image:SetColorTexture(1, 1, 1, 1) - ImageObject.image:SetGradientAlpha(texture.gradient, fromR, fromG, fromB, fromA, toR, toG, toB, toA) + ImageObject.image:SetGradientAlpha(gradientTable.gradient, fromR, fromG, fromB, fromA, toR, toG, toB, toA) end else local r, g, b, a = detailsFramework:ParseColors(texture) @@ -352,7 +398,10 @@ detailsFramework:Mixin(ImageMetaFunctions, detailsFramework.ScriptHookMixin) end end else - ImageObject.image:SetTexture(texture) + local textureType = type(texture) + if (textureType == "string" or textureType == "number") then + ImageObject.image:SetTexture(texture) + end end end @@ -360,6 +409,13 @@ detailsFramework:Mixin(ImageMetaFunctions, detailsFramework.ScriptHookMixin) ImageObject.image:SetTexCoord(unpack(texCoord)) end + if (width) then + ImageObject.image:SetWidth(width) + end + if (height) then + ImageObject.image:SetHeight(height) + end + ImageObject.HookList = { } @@ -385,4 +441,272 @@ function detailsFramework:CreateHighlightTexture(parent, parentKey, alpha, name) end return highlightTexture -end \ No newline at end of file +end + +---Set an atlas to a texture object +---Accpets a string (atlasname) or a table (atlasinfo) +---@param self table +---@param textureObject texture +---@param atlas atlasinfo|atlasname +---@param useAtlasSize boolean? +---@param filterMode texturefilter? +---@param resetTexCoords boolean? +function detailsFramework:SetAtlas(textureObject, atlas, useAtlasSize, filterMode, resetTexCoords) + local isAtlas = C_Texture.GetAtlasInfo(type(atlas) == "string" and atlas or "--") + if (isAtlas and type(atlas) == "string") then + textureObject:SetAtlas(atlas, useAtlasSize, filterMode, resetTexCoords) + return + end + + if (type(atlas) == "table") then + ---@cast atlas df_atlasinfo + local atlasInfo = atlas + + local atlasName = atlas.atlas + if (atlasName) then + isAtlas = C_Texture.GetAtlasInfo(atlasName) + if (isAtlas) then + textureObject:SetAtlas(atlasName, useAtlasSize, filterMode, resetTexCoords) + return + end + end + + if (useAtlasSize) then + if (atlasInfo.width) then + textureObject:SetWidth(atlasInfo.width) + end + if (atlasInfo.height) then + textureObject:SetHeight(atlasInfo.height) + end + end + + textureObject:SetHorizTile(atlasInfo.tilesHorizontally or false) + textureObject:SetVertTile(atlasInfo.tilesVertically or false) + + textureObject:SetTexture(atlasInfo.file, atlasInfo.tilesHorizontally and "REPEAT" or "CLAMP", atlasInfo.tilesVertically and "REPEAT" or "CLAMP", filterMode or "LINEAR") + textureObject:SetTexCoord(atlasInfo.leftTexCoord or 0, atlasInfo.rightTexCoord or 1, atlasInfo.topTexCoord or 0, atlasInfo.bottomTexCoord or 1) + + if (atlasInfo.desaturated) then + textureObject:SetDesaturated(true) + else + textureObject:SetDesaturated(false) + if (atlasInfo.desaturation) then + textureObject:SetDesaturation(atlasInfo.desaturation) + end + end + + if (atlasInfo.colorName) then + textureObject:SetVertexColor(detailsFramework:ParseColors(atlasInfo.colorName)) + else + if (atlasInfo.vertexRed or atlasInfo.vertexGreen or atlasInfo.vertexBlue or atlasInfo.vertexAlpha) then + textureObject:SetVertexColor(atlasInfo.vertexRed or 1, atlasInfo.vertexGreen or 1, atlasInfo.vertexBlue or 1, atlasInfo.vertexAlpha or 1) + end + end + + elseif (type(atlas) == "string" or type(atlas) == "number") then + ---@cast atlas string + textureObject:SetTexture(atlas) + end +end + +---get the passed atlas, convert it to string with a texture escape sequence, and return it +---textureHeight overrides the height of the atlas +---textureWidth overrides the width of the atlas +---@param self table +---@param atlas atlasinfo|atlasname +---@param textureHeight number? +---@param textureWidth number? +---@return string +function detailsFramework:CreateAtlasString(atlas, textureHeight, textureWidth) + local file, width, height, leftTexCoord, rightTexCoord, topTexCoord, bottomTexCoord, r, g, b, a, nativeWidth, nativeHeight = detailsFramework:ParseTexture(atlas) + + nativeWidth = nativeWidth or width or textureWidth + nativeHeight = nativeHeight or height or textureHeight + + if (not height) then + return "|T" .. file .. "|t" + elseif (not width) then + return "|T" .. file .. ":" .. height .. "|t" + elseif (not leftTexCoord) then + return "|T" .. file .. ":" .. height .. ":" .. width .. "|t" + elseif (not r) then + --the two zeros are the x and y offset + --texCoords are multiplied by the heigh and width to get the actual pixel position + local str = "|T" .. file .. ":" .. (textureHeight or height) .. ":" .. (textureWidth or width) .. ":0:0:" .. nativeWidth .. ":" .. nativeHeight .. ":" .. math.floor(leftTexCoord*nativeWidth) .. ":" .. math.floor(rightTexCoord*nativeWidth) .. ":" .. math.floor(topTexCoord*nativeHeight) .. ":" .. math.floor(bottomTexCoord*nativeHeight) .. "|t" + return str + else + return "|T" .. file .. ":" .. (textureHeight or height) .. ":" .. (textureWidth or width) .. ":0:0:" .. nativeWidth .. ":" .. nativeHeight .. ":" .. math.floor(leftTexCoord*nativeWidth) .. ":" .. math.floor(rightTexCoord*nativeWidth) .. ":" .. math.floor(topTexCoord*nativeHeight) .. ":" .. math.floor(bottomTexCoord*nativeHeight) .. ":" .. r .. ":" .. g .. ":" .. b .. "|t" + end +end + +---Receives a texturepath or a textureid or an atlasname or an atlasinfo. +---Parse the data received and return the texture path or id, width, height and texcoords, what is available. +---nativeWidth and nativeHeight are the dimentions of the texture file in pixels. +---@param self table +---@param texture texturepath|textureid|atlasname|atlasinfo +---@param width number? +---@param height number? +---@param leftTexCoord number? +---@param rightTexCoord number? +---@param topTexCoord number? +---@param bottomTexCoord number? +---@param vertexRed number? +---@param vertexGreen number? +---@param vertexBlue number? +---@param vertexAlpha number? +---@return any texture +---@return number? width +---@return number? height +---@return number? leftTexCoord +---@return number? rightTexCoord +---@return number? topTexCoord +---@return number? bottomTexCoord +---@return number? red +---@return number? green +---@return number? blue +---@return number? alpha +---@return number? nativeWidth +---@return number? nativeHeight +function detailsFramework:ParseTexture(texture, width, height, leftTexCoord, rightTexCoord, topTexCoord, bottomTexCoord, vertexRed, vertexGreen, vertexBlue, vertexAlpha) + local isAtlas + if (type(texture) == "string") then + isAtlas = C_Texture.GetAtlasInfo(texture) + end + + if (isAtlas) then + --ui atlasinfo + ---@type atlasinfo + local atlasInfo = isAtlas + local textureId = atlasInfo.file + local texturePath = atlasInfo.filename + return textureId or texturePath, width or atlasInfo.width, height or atlasInfo.height, atlasInfo.leftTexCoord, atlasInfo.rightTexCoord, atlasInfo.topTexCoord, atlasInfo.bottomTexCoord + end + + if (type(texture) == "table") then + ---@type df_atlasinfo + local atlasInfo = texture + + local r, g, b, a + if (type(atlasInfo.colorName) == "string") then + r, g, b, a = detailsFramework:ParseColors(atlasInfo.colorName) + else + r, g, b, a = atlasInfo.vertexRed or vertexRed, atlasInfo.vertexGreen or vertexGreen, atlasInfo.vertexBlue or vertexBlue, atlasInfo.vertexAlpha or vertexAlpha + end + + local nativeWidth, nativeHeight = atlasInfo.nativeWidth, atlasInfo.nativeHeight + return atlasInfo.file or atlasInfo.filename, width or atlasInfo.width, height or atlasInfo.height, atlasInfo.leftTexCoord or 0, atlasInfo.rightTexCoord or 1, atlasInfo.topTexCoord or 0, atlasInfo.bottomTexCoord or 1, r, g, b, a, nativeWidth, nativeHeight + end + + if (type(vertexRed) == "string" or type(vertexRed) == "table") then + --the color passed is a colorName or a colorTable + vertexRed, vertexGreen, vertexBlue, vertexAlpha = detailsFramework:ParseColors(vertexRed) + end + + return texture, width, height, leftTexCoord or 0, rightTexCoord or 1, topTexCoord or 0, bottomTexCoord or 1, vertexRed, vertexGreen, vertexBlue, vertexAlpha +end + +---Use the passed arguments to create a table imitate an atlasinfo +---@param self table +---@param file any +---@param width number? width of the texture +---@param height number? height of the texture +---@param leftTexCoord number? left texture coordinate to use with SetTexCoord as firt parameter +---@param rightTexCoord number? right texture coordinate to use with SetTexCoord as second parameter +---@param topTexCoord number? top texture coordinate to use with SetTexCoord as third parameter +---@param bottomTexCoord number? bottom texture coordinate to use with SetTexCoord as fourth parameter +---@param tilesHorizontally boolean? if the texture should tile horizontally, used with texture:SetHorizTile(value) +---@param tilesVertically boolean? if the texture should tile vertically, used with texture:SetVertTile(value) +---@param vertexRed number|string? red color to use with SetVertexColor or a color name to be parsed with ParseColors +---@param vertexGreen number? green color to use with SetVertexColor +---@param vertexBlue number? blue color to use with SetVertexColor +---@param vertexAlpha number? alpha color to use with SetVertexColor +---@param desaturated boolean? if the texture should be desaturated +---@param desaturation number? the amount of desaturation to use with SetDesaturation +---@param alpha number? the alpha to use with SetAlpha +---@return df_atlasinfo +function detailsFramework:CreateAtlas(file, width, height, leftTexCoord, rightTexCoord, topTexCoord, bottomTexCoord, tilesHorizontally, tilesVertically, vertexRed, vertexGreen, vertexBlue, vertexAlpha, desaturated, desaturation, alpha) + ---@type df_atlasinfo + local atlasInfo = { + file = file, + width = width or 64, + height = height or 64, + leftTexCoord = leftTexCoord or 0, + rightTexCoord = rightTexCoord or 1, + topTexCoord = topTexCoord or 0, + bottomTexCoord = bottomTexCoord or 1, + tilesHorizontally = tilesHorizontally or false, + tilesVertically = tilesVertically or false, + desaturated = desaturated, + desaturation = desaturation, + alpha = alpha, + } + + --parse the colors passed + if (vertexRed) then + if (type(vertexRed) == "string") then + atlasInfo.colorName = vertexRed + else + atlasInfo.vertexRed = vertexRed + atlasInfo.vertexGreen = vertexGreen + atlasInfo.vertexBlue = vertexBlue + atlasInfo.vertexAlpha = vertexAlpha + end + end + + return atlasInfo +end + +---Return the texture passed can be parsed as a texture +---@param self table +---@param texture any +---@param bCheckTextureObject boolean? +---@return boolean +function detailsFramework:IsTexture(texture, bCheckTextureObject) + --if is a string, can be a path or an atlasname, so can be parsed + if (type(texture) == "string") then + return true + end + + --if is a number, can be parsed + if (type(texture) == "number") then + return true + end + + if (type(texture) == "table") then + --gradient texture + if (texture.gradient) then + return true + end + + --part of an atlasinfo + if (texture.file or texture.filename) then + return true + end + + if (bCheckTextureObject) then + --check if is a texture object + if (texture.GetTexture and texture.GetObjectType and texture:GetObjectType() == "Texture") then + return true + end + end + end + + return false +end + +---Receives a texture object and a texture to use as mask +---If the mask texture is not created, it will be created and added to a key named MaskTexture +---@param self table +---@param texture texture +---@param maskTexture string|number +function detailsFramework:SetMask(texture, maskTexture) + if (not texture.MaskTexture) then + local parent = texture:GetParent() + local maskTextureObject = parent:CreateMaskTexture(nil, "artwork") + maskTextureObject:SetAllPoints(texture) + texture:AddMaskTexture(maskTextureObject) + texture.MaskTexture = maskTextureObject + end + texture.MaskTexture:SetTexture(maskTexture) +end + diff --git a/libs/DF/rounded_panel.lua b/libs/DF/rounded_panel.lua index d7e3d998..aab3aa07 100644 --- a/libs/DF/rounded_panel.lua +++ b/libs/DF/rounded_panel.lua @@ -111,14 +111,14 @@ local cornerNames = {"TopLeft", "TopRight", "BottomLeft", "BottomRight"} local setCornerPoints = function(self, textures, width, height, xOffset, yOffset, bIsBorder) for cornerName, thisTexture in pairs(textures) do PixelUtil.SetSize(thisTexture, width or 16, height or 16) - thisTexture:SetTexture(self.options.corner_texture) + thisTexture:SetTexture(self.options.corner_texture, "CLAMP", "CLAMP", "TRILINEAR") --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:SetTexture([[Interface\Azerite\AzeriteGoldRingRank2]], "CLAMP", "CLAMP", "TRILINEAR") --1940690 --thisTexture.MaskTexture:Hide() end @@ -201,6 +201,9 @@ detailsFramework.RoundedCornerPanelMixin = { PixelUtil.SetPoint(centerBlock, "bottomright", self.CornerTextures["BottomRight"], "topright", 0, 0) centerBlock:SetColorTexture(unpack(defaultColorTable)) + self:CreateBorder() + self:SetBorderCornerColor(0, 0, 0, 0) + self.CenterTextures[#self.CenterTextures+1] = topHorizontalEdge self.CenterTextures[#self.CenterTextures+1] = bottomHorizontalEdge self.CenterTextures[#self.CenterTextures+1] = centerBlock @@ -300,7 +303,7 @@ detailsFramework.RoundedCornerPanelMixin = { ---@type height local frameHeight = self:GetHeight() - if (frameHeight < 32) then + if (false and frameHeight < 32) then local newCornerSize = frameHeight / 2 --set the new size of the corners on all corner textures @@ -419,12 +422,18 @@ detailsFramework.RoundedCornerPanelMixin = { return self:GetHeight() - (borderTexture:GetHeight() * 2) + 2 elseif (alignment == "horizontal") then + if (self.tabSide) then + if (self.tabSide == "left" or self.tabSide == "right") then + return self:GetWidth() - (borderTexture:GetHeight() * 2) + 2 - borderTexture:GetHeight() + end + end return self:GetWidth() - (borderTexture:GetHeight() * 2) + 2 end error("df_roundedpanel:CalculateBorderEdgeSize(self, alignment) alignment must be 'vertical' or 'horizontal'") end, + ---create the border textures ---@param self df_roundedpanel CreateBorder = function(self) local r, g, b, a = 0, 0, 0, 0.8 @@ -487,6 +496,7 @@ detailsFramework.RoundedCornerPanelMixin = { self.bHasBorder = true end, + ---set the color of the titlebar ---@param self df_roundedpanel ---@param red any ---@param green number|nil @@ -499,6 +509,7 @@ detailsFramework.RoundedCornerPanelMixin = { end end, + ---set the color of the border corners ---@param self df_roundedpanel ---@param red any ---@param green number|nil @@ -520,6 +531,7 @@ detailsFramework.RoundedCornerPanelMixin = { end end, + ---set the background color of the rounded panel ---@param self df_roundedpanel ---@param red any ---@param green number|nil diff --git a/libs/DF/scrollbox.lua b/libs/DF/scrollbox.lua index f315daa2..d259cc27 100644 --- a/libs/DF/scrollbox.lua +++ b/libs/DF/scrollbox.lua @@ -26,10 +26,12 @@ detailsFramework.ScrollBoxFunctions = { Refresh = function(self) --hide all frames and tag as not in use self._LinesInUse = 0 + --self.Frames has a list of frames used by the scrollbox for index, frame in ipairs(self.Frames) do if (not self.DontHideChildrenOnPreRefresh) then frame:Hide() end + --set the frame as not in use frame._InUse = nil end @@ -39,6 +41,7 @@ detailsFramework.ScrollBoxFunctions = { offset = self:GetOffsetFaux() end + --before starting the refresh, check if there's a pre refresh function and call it if (self.pre_refresh_func) then detailsFramework:Dispatch(self.pre_refresh_func, self, self.data, offset, self.LineAmount) end @@ -83,6 +86,9 @@ detailsFramework.ScrollBoxFunctions = { return self.Frames end, + ---@param self df_scrollbox + ---@param offset number + ---@return boolean OnVerticalScroll = function(self, offset) self:OnVerticalScrollFaux(offset, self.LineHeight, self.Refresh) return true @@ -109,12 +115,20 @@ detailsFramework.ScrollBoxFunctions = { return newLine end, + ---Creates multiple lines in the scroll box. + ---@param self df_scrollbox The DF_ScrollBox object. + ---@param callback function The callback function to be called for each line. + ---@param lineAmount number The number of lines to create. CreateLines = function(self, callback, lineAmount) for i = 1, lineAmount do self:CreateLine(callback) end end, + ---Retrieves a specific line from the scroll box. + ---@param self df_scrollbox The DF_ScrollBox object. + ---@param lineIndex number The index of the line to retrieve. + ---@return frame line The line object at the specified index. GetLine = function(self, lineIndex) local line = self.Frames[lineIndex] if (line) then @@ -125,6 +139,8 @@ detailsFramework.ScrollBoxFunctions = { return line end, + ---Sets the data for the scroll box. + ---@param data table The data to be set. SetData = function(self, data) self.data = data if (self.OnSetData) then @@ -132,26 +148,45 @@ detailsFramework.ScrollBoxFunctions = { end end, + ---Retrieves the data associated with the scrollbox. + ---@param self df_scrollbox + ---@return table The data associated with the scrollbox. GetData = function(self) return self.data end, + ---Retrieves the frames contained within the scrollbox. + ---@param self df_scrollbox + ---@return table The frames contained within the scrollbox. GetFrames = function(self) return self.Frames end, - GetLines = function(self) --alias of GetFrames + ---Retrieves the lines contained within the scrollbox. + ---This is an alias of GetFrames. + ---@param self df_scrollbox + ---@return table The lines contained within the scrollbox. + GetLines = function(self) return self.Frames end, + ---Retrieves the number of frames created within the scrollbox. + ---@param self df_scrollbox + ---@return number The number of frames created within the scrollbox. GetNumFramesCreated = function(self) return #self.Frames end, + ---get the amount of lines the scroll is currently showing + ---@param self df_scrollbox + ---@return number amountOfLines GetNumFramesShown = function(self) return self.LineAmount end, + ---set the max amount of lines the scroll can show + ---@param self df_scrollbox + ---@param newAmount number SetNumFramesShown = function(self, newAmount) --hide frames which won't be used if (newAmount < #self.Frames) then @@ -331,11 +366,11 @@ local grid_scrollbox_options = { ---create a scrollbox with a grid layout ---@param parent frame ---@param name string ----@param refreshFunc function +---@param refreshFunc fun(button:frame, data:table) ---@param data table ----@param createColumnFrameFunc function +---@param createColumnFrameFunc fun(line:frame, lineIndex:number, columnIndex:number) ---@param options df_gridscrollbox_options? ----@return unknown +---@return df_gridscrollbox function detailsFramework:CreateGridScrollBox(parent, name, refreshFunc, data, createColumnFrameFunc, options) options = options or {} @@ -425,9 +460,119 @@ function detailsFramework:CreateGridScrollBox(parent, name, refreshFunc, data, c scrollBox.OnSetData = onSetData onSetData(scrollBox, data) + ---@cast scrollBox df_gridscrollbox return scrollBox end +---create a scrollbox with a grid layout to be used as a menu +---@param parent frame +---@param name string? +---@param refreshMeFunc fun(gridScrollBox:df_gridscrollbox, searchText:string) +---@param refreshButtonFunc fun(button:button, data:table) +---@param clickFunc fun(button:button, data:table) +---@param onCreateButton fun(button:button, lineIndex:number, columnIndex:number) +---@param gridScrollBoxOptions df_gridscrollbox_options +---@return df_gridscrollbox +function detailsFramework:CreateMenuWithGridScrollBox(parent, name, refreshMeFunc, refreshButtonFunc, clickFunc, onCreateButton, gridScrollBoxOptions) + local dataSelected = nil + local gridScrollBox + + local onClickButtonSelectorButton = function(blizzButton, buttonDown, dfButton, data) + dataSelected = data + gridScrollBox:Refresh() + xpcall(clickFunc, geterrorhandler(), dfButton, data) + end + + --create a search bar to filter the auras + local searchText = "" + local onSearchTextChangedCallback = function(self, ...) + local text = self:GetText() + searchText = string.lower(text) + dataSelected = nil + gridScrollBox:RefreshMe() + end + + local searchBox = detailsFramework:CreateSearchBox(parent, onSearchTextChangedCallback) + + ---when the scroll is refreshing the line, the line will call this function for each selection button on it + ---@param button df_button + ---@param data table + local refreshLine = function(button, data) + button.data = data + + if (data.tooltip) then + button.tooltip = data.tooltip + end + + --set what happen when the user clicks the button + button:SetClickFunction(onClickButtonSelectorButton, button, data) + + if (button.data == dataSelected) then + button.widget:SetBorderCornerColor(.9, .9, .9) + else + button.widget:SetBorderCornerColor(unpack(gridScrollBoxOptions.roundedFramePreset.border_color)) + end + + xpcall(refreshButtonFunc, geterrorhandler(), button, data) + end + + --create a line + local createButton = function(line, lineIndex, columnIndex) + local width = gridScrollBoxOptions.width / gridScrollBoxOptions.columns_per_line - 5 + local height = gridScrollBoxOptions.line_height + if (not height) then + height = 30 + end + + local button = detailsFramework:CreateButton(line, onClickButtonSelectorButton, width, height) + detailsFramework:AddRoundedCornersToFrame(button.widget, gridScrollBoxOptions.roundedFramePreset) + button.textsize = 11 + + button:SetHook("OnEnter", function(self) + local dfButton = self:GetObject() + GameCooltip:Reset() + if (dfButton.spellId) then + GameCooltip:SetSpellByID(dfButton.spellId) + GameCooltip:SetOwner(self) + GameCooltip:Show() + end + self:SetBorderCornerColor(.9, .9, .9) + end) + + button:SetHook("OnLeave", function(self) + GameCooltip:Hide() + local dfButton = self:GetObject() + if (dfButton.data == dataSelected) then + self:SetBorderCornerColor(.9, .9, .9) + else + self:SetBorderCornerColor(unpack(gridScrollBoxOptions.roundedFramePreset.border_color)) + end + end) + + xpcall(onCreateButton, geterrorhandler(), button, lineIndex, columnIndex) + + return button + end + + gridScrollBox = detailsFramework:CreateGridScrollBox(parent, name, refreshLine, {}, createButton, gridScrollBoxOptions) + gridScrollBox:SetBackdrop({}) + gridScrollBox:SetBackdropColor(0, 0, 0, 0) + gridScrollBox:SetBackdropBorderColor(0, 0, 0, 0) + gridScrollBox.__background:Hide() + gridScrollBox:Show() + + gridScrollBox.searchBox = searchBox + + searchBox:SetPoint("bottomleft", gridScrollBox, "topleft", 0, 2) + searchBox:SetWidth(gridScrollBoxOptions.width) + + function gridScrollBox:RefreshMe() + xpcall(refreshMeFunc, geterrorhandler(), gridScrollBox, searchBox:GetText()) + end + + return gridScrollBox +end + --Need to test this and check the "same_name_spells_add(value)" on the OnEnter function --also need to make sure this can work with any data (global, class, spec) and aura type (buff, debuff) diff --git a/libs/DF/slider.lua b/libs/DF/slider.lua index 56c6a1c9..3f991a90 100644 --- a/libs/DF/slider.lua +++ b/libs/DF/slider.lua @@ -885,13 +885,26 @@ local get_switch_func = function(self) return self.OnSwitch end -local setCheckedTexture = function(self, texture, xOffSet, yOffSet) - self.checked_texture:SetTexture(texture) +local setCheckedTexture = function(self, texture, xOffSet, yOffSet, sizePercent, color) + if (texture) then + self.checked_texture:SetTexture(texture, "CLAMP", "CLAMP", "TRILINEAR") + end + if (xOffSet or yOffSet) then self.checked_texture:SetPoint("center", self.button, "center", xOffSet or -1, yOffSet or -1) else self.checked_texture:SetPoint("center", self.button, "center", -1, -1) end + + if (sizePercent and type(sizePercent) == "number") then + local width = self:GetWidth() * sizePercent + self.checked_texture:SetSize(width, width) + end + + if (color) then + local r, g, b, a = DF:ParseColors(color) + self.checked_texture:SetVertexColor(r, g, b, a) + end end local set_as_checkbok = function(self) @@ -904,6 +917,8 @@ local set_as_checkbok = function(self) self.checked_texture = checked self.SetCheckedTexture = setCheckedTexture + self.SetChecked = switch_set_value + self.GetChecked = switch_get_value self._thumb:Hide() self._text:Hide() @@ -926,7 +941,7 @@ local set_as_checkbok = function(self) end end ----@class df_checkbox : df_button +---@class df_checkbox : df_button, df_widgets ---@field OnSwitch fun(self:df_checkbox, fixedValue:any, value:boolean) ---@field SetValue fun(self:df_button, value:boolean) ---@field GetValue fun(self:df_button):boolean @@ -977,6 +992,7 @@ function DF:NewSwitch(parent, container, name, member, width, height, leftText, local slider = DF:NewButton(parent, container, name, member, width, height) slider.HookList.OnSwitch = {} + slider.type = "switch" slider.switch_func = switch_func slider.return_func = return_func @@ -1041,6 +1057,8 @@ function DF:NewSwitch(parent, container, name, member, width, height, leftText, end function DFSliderMetaFunctions:SetTemplate(template) + template = DF:ParseTemplate(self.type, template) + --slider e switch if (template.width) then PixelUtil.SetWidth(self.widget, template.width) @@ -1074,9 +1092,29 @@ function DFSliderMetaFunctions:SetTemplate(template) if (template.thumbtexture) then if (self.thumb) then - self.thumb:SetTexture(template.thumbtexture) + DF:SetAtlas(self.thumb, template.thumbtexture) + end + end + + if (template.slider_left) then + if (self.slider_left) then + DF:SetAtlas(self.slider_left, template.slider_left) + end + end + + if (template.slider_right) then + if (self.slider_right) then + DF:SetAtlas(self.slider_right, template.slider_right) + end + end + + if (template.slider_middle) then + if (self.slider_middle) then + self:SetBackdrop(nil) + DF:SetAtlas(self.slider_middle, template.slider_middle) end end + if (template.thumbwidth) then if (self.thumb) then self.thumb:SetWidth(template.thumbwidth) @@ -1094,6 +1132,18 @@ function DFSliderMetaFunctions:SetTemplate(template) end end + if (template.amount_color) then + DF:SetFontColor(self.amt, template.amount_color) + end + + if (template.amount_outline) then + DF:SetFontOutline(self.amt, template.amount_outline) + end + + if (template.amount_size) then + DF:SetFontSize(self.amt, template.amount_size) + end + --switch only if (template.enabled_backdropcolor) then local r, g, b, a = DF:ParseColors(template.enabled_backdropcolor) @@ -1103,13 +1153,54 @@ function DFSliderMetaFunctions:SetTemplate(template) local r, g, b, a = DF:ParseColors(template.disabled_backdropcolor) self.backdrop_disabledcolor = {r, g, b, a} end + + if (template.is_checkbox) then + self:SetAsCheckBox() + self:SetCheckedTexture(template.checked_texture, template.checked_xoffset or 0, template.checked_yoffset or 0, template.checked_size_percent or 0.7, template.checked_color) + end + + if (template.rounded_corner) then + self:SetBackdrop(nil) + DF:AddRoundedCornersToFrame(self.widget or self, template.rounded_corner) + end end -function DF:CreateSlider (parent, w, h, min, max, step, defaultv, isDecemal, member, name, with_label, slider_template, label_template) - local slider, label = DF:NewSlider (parent, parent, name, member, w, h, min, max, step, defaultv, isDecemal, false, with_label, slider_template, label_template) - return slider, label +--DF:Mixin(DFSliderMetaFunctions, DF.SetPointMixin) +--DF:Mixin(DFSliderMetaFunctions, DF.FrameMixin) +--DF:Mixin(DFSliderMetaFunctions, DF.TooltipHandlerMixin) + +---@class df_slider : slider, df_scripthookmixin, df_widgets +---@field widget slider +---@field slider slider +---@field type string +---@field dframework boolean +---@field SetTemplate fun(self:df_slider, template: table|string) +---@field SetFixedParameter fun(value: any) +---@field GetFixedParameter fun() +---@field SetValueNoCallback fun(value: number) +---@field SetThumbSize fun(width:number, height:number) +---@field ClearFocus fun() + +---@param parent frame +---@param width number? default 150 +---@param height number? default 20 +---@param minValue number? default 1 +---@param maxValue number? default 2 +---@param step number? default 1 +---@param defaultv number? default to minValue +---@param isDecemal boolean? default false +---@param member string? +---@param name string? +---@param label string? +---@param sliderTemplate string|table|nil +---@param labelTemplate string|table|nil +---@return df_slider, df_label? +function DF:CreateSlider (parent, width, height, minValue, maxValue, step, defaultv, isDecemal, member, name, label, sliderTemplate, labelTemplate) + local slider, labelText = DF:NewSlider(parent, parent, name, member, width, height, minValue, maxValue, step, defaultv, isDecemal, false, label, sliderTemplate, labelTemplate) + return slider, labelText end +---@return df_slider, df_label? function DF:NewSlider (parent, container, name, member, width, height, minValue, maxValue, step, defaultValue, isDecemal, isSwitch, with_label, slider_template, label_template) if (not name) then name = "DetailsFrameworkSlider" .. DF.SliderCounter @@ -1117,7 +1208,7 @@ function DF:NewSlider (parent, container, name, member, width, height, minValue, end if (not parent) then - return error("Details! FrameWork: parent not found.", 2) + error("Details! FrameWork: parent not found.", 2) end if (not container) then @@ -1125,7 +1216,7 @@ function DF:NewSlider (parent, container, name, member, width, height, minValue, end if (name:find("$parent")) then - local parentName = DF.GetParentName(parent) + local parentName = DF:GetParentName(parent) name = name:gsub("$parent", parentName) end @@ -1148,8 +1239,8 @@ function DF:NewSlider (parent, container, name, member, width, height, minValue, step = step or 1 defaultValue = defaultValue or minValue - width = width or 130 - height = height or 19 + width = width or 160 + height = height or 20 --default members SliderObject.lockdown = false @@ -1164,6 +1255,7 @@ function DF:NewSlider (parent, container, name, member, width, height, minValue, SliderObject.slider:SetValueStep(0.01) else SliderObject.slider:SetValueStep(step) + SliderObject.slider:SetObeyStepOnDrag(true) end if (not APISliderFunctions) then @@ -1198,6 +1290,22 @@ function DF:NewSlider (parent, container, name, member, width, height, minValue, SliderObject.slider:SetThumbTexture (SliderObject.thumb) SliderObject.slider.thumb = SliderObject.thumb + SliderObject.slider_left = SliderObject.slider:CreateTexture("$parentLeft", "artwork") + SliderObject.slider_left:SetPoint("topright", SliderObject.slider, "topleft", 0, 0) + SliderObject.slider_left:SetPoint("bottomright", SliderObject.slider, "bottomleft", 0, 0) + SliderObject.slider_left:SetWidth(11) + + SliderObject.slider_right = SliderObject.slider:CreateTexture("$parentRight", "artwork") + SliderObject.slider_right:SetPoint("topleft", SliderObject.slider, "topright", 0, 0) + SliderObject.slider_right:SetPoint("bottomleft", SliderObject.slider, "bottomright", 0, 0) + SliderObject.slider_right:SetWidth(11) + + SliderObject.slider_middle = SliderObject.slider:CreateTexture("$parentMiddle", "artwork") + SliderObject.slider_middle:SetPoint("topleft", SliderObject.slider_left, "topright", 0, 0) + SliderObject.slider_middle:SetPoint("bottomleft", SliderObject.slider_left, "bottomright", 0, 0) + SliderObject.slider_middle:SetPoint("topright", SliderObject.slider_right, "topleft", 0, 0) + SliderObject.slider_middle:SetPoint("bottomright", SliderObject.slider_right, "bottomleft", 0, 0) + if (not isSwitch) then SliderObject.have_tooltip = "Right Click to Type the Value" end diff --git a/libs/DF/split_bar.lua b/libs/DF/split_bar.lua index 254790c4..62e35eed 100644 --- a/libs/DF/split_bar.lua +++ b/libs/DF/split_bar.lua @@ -727,7 +727,7 @@ function DF:NewSplitBar (parent, container, name, member, w, h) end if (name:find("$parent")) then - local parentName = DF.GetParentName(parent) + local parentName = DF:GetParentName(parent) name = name:gsub("$parent", parentName) end diff --git a/libs/DF/textentry.lua b/libs/DF/textentry.lua index 81b81720..a8c4708e 100644 --- a/libs/DF/textentry.lua +++ b/libs/DF/textentry.lua @@ -596,7 +596,7 @@ function detailsFramework:NewTextEntry(parent, container, name, member, width, h end if (name:find("$parent")) then - local parentName = detailsFramework.GetParentName(parent) + local parentName = detailsFramework:GetParentName(parent) name = name:gsub("$parent", parentName) end @@ -722,6 +722,51 @@ function detailsFramework:NewTextEntry(parent, container, name, member, width, h return newTextEntryObject, withLabel end +---create a search box with no backdrop, a magnifying glass icon and a clear search button +---@param parent frame +---@param callback any +---@return df_textentry +function detailsFramework:CreateSearchBox(parent, callback) + local onSearchPressEnterCallback = function(_, _, text, self) + callback(self) + end + + local searchBox = detailsFramework:CreateTextEntry(parent, onSearchPressEnterCallback, 220, 26) + searchBox:SetAsSearchBox() + searchBox:SetTextInsets(25, 5, 0, 0) + searchBox:SetBackdrop(nil) + searchBox:SetHook("OnTextChanged", callback) + + local file, size, flags = searchBox:GetFont() + searchBox:SetFont(file, 12, flags) + searchBox.ClearSearchButton:SetAlpha(0) + + searchBox.BottomLineTexture = searchBox:CreateTexture(nil, "border") + searchBox.BottomLineTexture:SetPoint("bottomleft", searchBox.widget, "bottomleft", -15, 0) + searchBox.BottomLineTexture:SetPoint("bottomright", searchBox.widget, "bottomright", 0, 0) + local bUseAtlasSize = false + searchBox.BottomLineTexture:SetAtlas("common-slider-track") + searchBox.BottomLineTexture:SetHeight(8) + + --create the button to clear the search box + searchBox.ClearSearchButton = CreateFrame("button", nil, searchBox.widget, "UIPanelCloseButton") + searchBox.ClearSearchButton:SetPoint("right", searchBox.widget, "right", -3, 0) + searchBox.ClearSearchButton:SetSize(10, 10) + searchBox.ClearSearchButton:SetAlpha(0.3) + searchBox.ClearSearchButton:GetNormalTexture():SetAtlas("common-search-clearbutton") + searchBox.ClearSearchButton:GetHighlightTexture():SetAtlas("common-search-clearbutton") + searchBox.ClearSearchButton:GetPushedTexture():SetAtlas("common-search-clearbutton") + + searchBox.ClearSearchButton:SetScript("OnClick", function() + searchBox:SetText("") + searchBox:PressEnter() + searchBox:ClearFocus() + end) + + return searchBox +end + + function detailsFramework:NewSpellEntry(parent, func, width, height, param1, param2, member, name) local editbox = detailsFramework:NewTextEntry(parent, parent, name, member, width, height, func, param1, param2) return editbox @@ -1020,7 +1065,7 @@ end function detailsFramework:NewSpecialLuaEditorEntry(parent, width, height, member, name, nointent, showLineNumbers, bNoName) if (not bNoName) then if (name and name:find("$parent")) then - local parentName = detailsFramework.GetParentName(parent) + local parentName = detailsFramework:GetParentName(parent) name = name:gsub("$parent", parentName) end else diff --git a/libs/DF/timebar.lua b/libs/DF/timebar.lua index 031a66ef..bfc4a8d1 100644 --- a/libs/DF/timebar.lua +++ b/libs/DF/timebar.lua @@ -369,7 +369,7 @@ function DF:CreateTimeBar(parent, texture, width, height, value, member, name) end if (name:find("$parent")) then - local parentName = DF.GetParentName(parent) + local parentName = DF:GetParentName(parent) name = name:gsub("$parent", parentName) end diff --git a/media/track_minimaps/66710.tga b/media/track_minimaps/66710.tga new file mode 100644 index 0000000000000000000000000000000000000000..eef0c1a2eedd158e0c339e986f4c81e9e62acf8b GIT binary patch literal 1048620 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 literal 0 HcmV?d00001 diff --git a/racing_helper.lua b/racing_helper.lua index 7e95cab3..ed8ad8d3 100644 --- a/racing_helper.lua +++ b/racing_helper.lua @@ -59,21 +59,41 @@ dragonRidingRaceFrame:SetPoint("center", UIParent, "center", -400, 125) dragonRidingRaceFrame:RegisterEvent("QUEST_WATCH_LIST_CHANGED") detailsFramework:AddRoundedCornersToFrame(dragonRidingRaceFrame, detailsFramework.DefaultRoundedCornerPreset) dragonRidingRaceFrame:Hide() +dragonRidingRaceFrame:SetAlpha(0.1) local title = dragonRidingRaceFrame:CreateFontString("$parentTitle", "overlay", "GameFontNormal") title:SetPoint("bottomleft", dragonRidingRaceFrame, "topleft", 6, 2) title:SetText("World Quest Tracker - Race Track") +title:SetIgnoreParentAlpha(true) local minimapTexture = dragonRidingRaceFrame:CreateTexture("$parentMinimapTexture", "artwork") minimapTexture:SetSize(256, 256) minimapTexture:SetAllPoints(dragonRidingRaceFrame) +minimapTexture:SetIgnoreParentAlpha(true) +minimapTexture:SetAlpha(0.7) dragonRidingRaceFrame.MinimapTexture = minimapTexture -local positionBlip = dragonRidingRaceFrame:CreateTexture("$parentPositionBlip", "overlay") +local positionBlip = dragonRidingRaceFrame:CreateTexture("$parentPositionBlip", "overlay", nil, 0) positionBlip:SetTexture([[Interface\COMMON\Indicator-Yellow]]) -positionBlip:SetSize(20, 20) +positionBlip:SetSize(24, 24) +positionBlip:SetIgnoreParentAlpha(true) dragonRidingRaceFrame.PositionBlip = positionBlip +--make a ring around the position blip +local ringTexture = dragonRidingRaceFrame:CreateTexture("$parentRingTexture", "overlay", nil, 2) +ringTexture:SetTexture([[Interface\AddOns\WorldQuestTracker\media\border_zone_whiteT]]) +ringTexture:SetPoint("center", positionBlip, "center", 0, 0) +ringTexture:SetSize(36, 36) +ringTexture:SetIgnoreParentAlpha(true) + +--make a glow above the positionBlip +local glowTexture = dragonRidingRaceFrame:CreateTexture("$parentGlowTexture", "overlay", nil, 1) +glowTexture:SetTexture([[Interface\AddOns\WorldQuestTracker\media\highlight_circleT]]) +glowTexture:SetPoint("center", positionBlip, "center", 0, 0) +glowTexture:SetSize(24, 24) +glowTexture:SetAlpha(0.2) +glowTexture:SetIgnoreParentAlpha(true) + dragonRidingRaceFrame:SetScript("OnEvent", function(self, event, questId, bIsStartingRace) if (bIsStartingRace) then currentRaceId = questId @@ -99,6 +119,8 @@ dragonRidingRaceFrame:SetScript("OnEvent", function(self, event, questId, bIsSta dragonRidingRaceFrame:SetScale(WorldQuestTracker.db.profile.dragon_racing.minimap_scale) minimapTexture:SetVertexColor(unpack(WorldQuestTracker.db.profile.dragon_racing.minimap_track_color)) + SetPortraitTexture(positionBlip, "player") + for i = 1, #playerPathTextures do playerPathTextures[i]:Hide() end @@ -143,6 +165,7 @@ dragonRidingRaceFrame:SetScript("OnEvent", function(self, event, questId, bIsSta end end + dragonRidingRaceFrame:SetScript("OnUpdate", function() --get the player current position local x, y = translateWorldCoordinateToMinimapCoords() @@ -178,6 +201,7 @@ dragonRidingRaceFrame:SetScript("OnEvent", function(self, event, questId, bIsSta end) WQT_RaceData = { + --thaldrazus [70051] = { ["buffId"] = 415668, ["mapId"] = 2025, @@ -1675,6 +1699,308 @@ WQT_RaceData = { }, }, }, + --the waking shores + [66710] = { + ["toUnrealEngine"] = [[---,x,y + 1,"(0.91158306788837)","(0.64878031328809)" + 2,"(0.9145865285042)","(0.65976534621105)" + 3,"(0.96862260280257)","(0.63194864272751)" + 4,"(1)","(0.52073761500601)" + 5,"(0.95694712074141)","(0.40523104890814)" + 6,"(0.87124362604376)","(0.31544586827299)" + 7,"(0.70550929385085)","(0.23868373643925)" + 8,"(0.55159791314379)","(0.19893242167343)" + 9,"(0.47401711628456)","(0.26839080424921)" + 10,"(0.50112527363771)","(0.48691661719683)" + 11,"(0.48989998295909)","(0.60427443663505)" + 12,"(0.56938518358305)","(0.72315061125317)" + 13,"(0.60199722757482)","(0.86326677997736)" + 14,"(0.53598090107096)","(0.96657920762961)" + 15,"(0.39966344200191)","(1)" + 16,"(0.27783239608321)","(0.93320874412501)" + 17,"(0.1256824557264)","(0.83004063297947)" + 18,"(0.004055409178497)","(0.70664880699365)" + 19,"(0)","(0.55968124243172)" + 20,"(0.019973504660034)","(0.43768285901914)" + 21,"(0.058243868549032)","(0.30926602928897)" + 22,"(0.11745325219238)","(0.15013767673466)" + 23,"(0.18331719362408)","(0.028880886127606)" + 24,"(0.27998544968343)","(0)" + 25,"(0.35605263675331)","(0.072300750749021)" + 26,"(0.46687427084562)","(0.18447166515175)" + 27,"(0.54488518686015)","(0.27263813606136)" + 28,"(0.68591060731186)","(0.41382242884681)" + 29,"(0.78490765136917)","(0.50270017396809)" + 30,"(0.89733383472938)","(0.60782989813559)" + 31,"(0.91161583887163)","(0.64732198892401)" + ]], + ["mapId"] = 2022, + ["maxXNormalized"] = 1, + ["startX"] = 0.62841761112213, + ["minYNormalized"] = 0, + ["minX"] = 0.49577212333679, + ["worldPositionsNormalized"] = { + [1] = { + [1] = 0.91158306788837, + [2] = 0.64878031328809, + }, + [2] = { + [1] = 0.9145865285042, + [2] = 0.65976534621105, + }, + [3] = { + [1] = 0.96862260280257, + [2] = 0.63194864272751, + }, + [4] = { + [1] = 1, + [2] = 0.52073761500601, + }, + [5] = { + [1] = 0.95694712074141, + [2] = 0.40523104890814, + }, + [6] = { + [1] = 0.87124362604376, + [2] = 0.31544586827299, + }, + [7] = { + [1] = 0.70550929385085, + [2] = 0.23868373643925, + }, + [8] = { + [1] = 0.55159791314379, + [2] = 0.19893242167343, + }, + [9] = { + [1] = 0.47401711628456, + [2] = 0.26839080424921, + }, + [10] = { + [1] = 0.50112527363771, + [2] = 0.48691661719683, + }, + [11] = { + [1] = 0.48989998295909, + [2] = 0.60427443663505, + }, + [12] = { + [1] = 0.56938518358305, + [2] = 0.72315061125317, + }, + [13] = { + [1] = 0.60199722757482, + [2] = 0.86326677997736, + }, + [14] = { + [1] = 0.53598090107096, + [2] = 0.96657920762961, + }, + [15] = { + [1] = 0.39966344200191, + [2] = 1, + }, + [16] = { + [1] = 0.27783239608321, + [2] = 0.93320874412501, + }, + [17] = { + [1] = 0.1256824557264, + [2] = 0.83004063297947, + }, + [18] = { + [1] = 0.004055409178497, + [2] = 0.70664880699365, + }, + [19] = { + [1] = 0, + [2] = 0.55968124243172, + }, + [20] = { + [1] = 0.019973504660034, + [2] = 0.43768285901914, + }, + [21] = { + [1] = 0.058243868549032, + [2] = 0.30926602928897, + }, + [22] = { + [1] = 0.11745325219238, + [2] = 0.15013767673466, + }, + [23] = { + [1] = 0.18331719362408, + [2] = 0.028880886127606, + }, + [24] = { + [1] = 0.27998544968343, + [2] = 0, + }, + [25] = { + [1] = 0.35605263675331, + [2] = 0.072300750749021, + }, + [26] = { + [1] = 0.46687427084562, + [2] = 0.18447166515175, + }, + [27] = { + [1] = 0.54488518686015, + [2] = 0.27263813606136, + }, + [28] = { + [1] = 0.68591060731186, + [2] = 0.41382242884681, + }, + [29] = { + [1] = 0.78490765136917, + [2] = 0.50270017396809, + }, + [30] = { + [1] = 0.89733383472938, + [2] = 0.60782989813559, + }, + [31] = { + [1] = 0.91161583887163, + [2] = 0.64732198892401, + }, + }, + ["maxY"] = 0.81091785430908, + ["startY"] = 0.74158334732056, + ["startYNormalized"] = 0.64732198892401, + ["maxX"] = 0.64127802848816, + ["minXNormalized"] = 0, + ["minY"] = 0.61432349681854, + ["maxYNormalized"] = 1, + ["startXNormalized"] = 0.91161583887163, + ["worldPositions"] = { + [1] = { + [1] = 0.62841284275055, + [2] = 0.74187004566193, + }, + [2] = { + [1] = 0.62884986400604, + [2] = 0.74402964115143, + }, + [3] = { + [1] = 0.63671243190765, + [2] = 0.73856103420258, + }, + [4] = { + [1] = 0.64127802848816, + [2] = 0.7166975736618, + }, + [5] = { + [1] = 0.63501358032227, + [2] = 0.69398963451385, + }, + [6] = { + [1] = 0.62254321575165, + [2] = 0.67633837461472, + }, + [7] = { + [1] = 0.59842789173126, + [2] = 0.66124737262726, + }, + [8] = { + [1] = 0.57603287696838, + [2] = 0.65343248844147, + }, + [9] = { + [1] = 0.56474441289902, + [2] = 0.66708761453629, + }, + [10] = { + [1] = 0.56868880987167, + [2] = 0.71004855632782, + }, + [11] = { + [1] = 0.56705546379089, + [2] = 0.73312044143677, + }, + [12] = { + [1] = 0.57862102985382, + [2] = 0.75649082660675, + }, + [13] = { + [1] = 0.58336627483368, + [2] = 0.78403687477112, + }, + [14] = { + [1] = 0.57376050949097, + [2] = 0.8043475151062, + }, + [15] = { + [1] = 0.55392551422119, + [2] = 0.81091785430908, + }, + [16] = { + [1] = 0.53619837760925, + [2] = 0.79778707027435, + }, + [17] = { + [1] = 0.51405966281891, + [2] = 0.77750480175018, + }, + [18] = { + [1] = 0.49636220932007, + [2] = 0.75324666500092, + }, + [19] = { + [1] = 0.49577212333679, + [2] = 0.72435367107391, + }, + [20] = { + [1] = 0.4986783862114, + [2] = 0.70036947727203, + }, + [21] = { + [1] = 0.50424695014954, + [2] = 0.67512345314026, + }, + [22] = { + [1] = 0.51286226511002, + [2] = 0.64383971691132, + }, + [23] = { + [1] = 0.52244585752487, + [2] = 0.62000131607056, + }, + [24] = { + [1] = 0.53651165962219, + [2] = 0.61432349681854, + }, + [25] = { + [1] = 0.54757988452911, + [2] = 0.62853741645813, + }, + [26] = { + [1] = 0.56370508670807, + [2] = 0.65058958530426, + }, + [27] = { + [1] = 0.57505613565445, + [2] = 0.66792261600494, + }, + [28] = { + [1] = 0.59557616710663, + [2] = 0.69567865133286, + }, + [29] = { + [1] = 0.6099808216095, + [2] = 0.71315151453018, + }, + [30] = { + [1] = 0.62633949518204, + [2] = 0.73381942510605, + }, + [31] = { + [1] = 0.62841761112213, + [2] = 0.74158334732056, + }, + }, + }, + } WQT_UseSameTrack = {