local Plater = Plater local GameCooltip = GameCooltip2 local DF = DetailsFramework local _ --get templates local options_text_template = DF:GetTemplate ("font", "OPTIONS_FONT_TEMPLATE") local options_dropdown_template = DF:GetTemplate ("dropdown", "OPTIONS_DROPDOWN_TEMPLATE") local options_switch_template = DF:GetTemplate ("switch", "OPTIONS_CHECKBOX_TEMPLATE") local options_slider_template = DF:GetTemplate ("slider", "OPTIONS_SLIDER_TEMPLATE") local options_button_template = DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE") local scrollbox_size = {201, 405} local scrollbox_lines = 11 local scrollbox_line_height = 28.7 local scrollbox_line_backdrop_color = {0, 0, 0, 0.5} local scrollbox_line_backdrop_color_selected = {.6, .6, .1, 0.7} local buttons_size = {120, 20} local luaeditor_backdrop_color = {.2, .2, .2, .5} local luaeditor_border_color = {0, 0, 0, 1} local debugmode = false local PLATER_OPTIONS_ANIMATION_TAB = 20 function Plater.CreateSpellAnimationPanel() local f = PlaterOptionsPanelFrame local mainFrame = PlaterOptionsPanelContainer local animationFrame = mainFrame.AllFrames [PLATER_OPTIONS_ANIMATION_TAB] --store which animation is being edited local currentAnimation local currentCopy local previewEnabled = true local previewLoopTime = 1 animationFrame.CurrentIndex = 1 animationFrame.SearchString = "" animationFrame.AvailableSpells = {} --set points local startX = 10 local startY = -220 --menu and settings panel local startYGeneralSettings = -150 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ local CLEUFrame = CreateFrame ("frame") CLEUFrame.SpellCaptured = {} CLEUFrame.PlayerSerial = UnitGUID ("player") CLEUFrame:SetScript ("OnEvent", function (self, event) local time, token, hidding, sourceGUID, sourceName, sourceFlag, sourceFlag2, targetGUID, targetName, targetFlag, targetFlag2, spellID, spellName, spellType, amount, overKill, school, resisted, blocked, absorbed, isCritical = CombatLogGetCurrentEventInfo() if (token == "SPELL_DAMAGE" or token == "SPELL_PERIODIC_DAMAGE") then if (CLEUFrame.PlayerSerial == sourceGUID) then if (not CLEUFrame.SpellCaptured [spellID]) then CLEUFrame.SpellCaptured [spellID] = {Token = token, Name = spellName, ID = spellID} animationFrame.SelectSpellDropdown:Refresh() end end end end) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ --> logic function animationFrame.LoopPreview() --simulate a hit in the nameplate if (currentAnimation and #currentAnimation > 0) then local spellName = GetSpellInfo (currentAnimation.info.spellid) if (spellName and Plater.SPELL_WITH_ANIMATIONS [spellName]) then for _, plateFrame in ipairs (Plater.GetAllShownPlates()) do Plater.DoNameplateAnimation (plateFrame, Plater.SPELL_WITH_ANIMATIONS [spellName], spellName, false) end end end end function animationFrame.StopPreview() if (animationFrame.PreviewTicker) then animationFrame.PreviewTicker:Cancel() end end function animationFrame.UpdatePreview (newLoopTime) if (animationFrame.PreviewTicker) then animationFrame.PreviewTicker:Cancel() end previewLoopTime = newLoopTime or previewLoopTime if (previewEnabled) then animationFrame.PreviewTicker = C_Timer.NewTicker (previewLoopTime, animationFrame.LoopPreview) end end animationFrame:HookScript ("OnShow", function() animationFrame.BuildAnimationDataForScroll() CLEUFrame:RegisterEvent ("COMBAT_LOG_EVENT_UNFILTERED") Plater.RefreshIsEditingAnimations (true) if (previewEnabled) then animationFrame.UpdatePreview() end end) animationFrame:HookScript ("OnHide", function() CLEUFrame:UnregisterEvent ("COMBAT_LOG_EVENT_UNFILTERED") Plater.RefreshIsEditingAnimations (false) animationFrame.StopPreview() end) function animationFrame.GetAnimation (spellID) return Plater.db.profile.spell_animation_list [spellID] end --runs when clicking in the add animation button function animationFrame.AddNewAnimation() --get the option selected in the dropdown local spellID = animationFrame.SelectSpellDropdown.value if (not spellID or type (spellID) ~= "number") then return end --check if there's an animation for this spell local db = Plater.db.profile.spell_animation_list if (db [spellID]) then Plater:Msg ("an animation for this spell already exists.") return end local _, playerClass = UnitClass ("player") --add the spell to the animation list local newAnimationTable = { info = { time = time(), desc = "", class = playerClass, spellid = spellID, } } db [spellID] = newAnimationTable --refresh the scrollbox animationFrame.BuildAnimationDataForScroll() --start editing this new animation animationFrame.EditAnimation (spellID) end function animationFrame.ShowImportTextField() animationFrame.ImportAnimation() end --when a text in the searchi field is changed, get the text and update the animation list function animationFrame.OnSearchBoxTextChanged() local text = animationFrame.AnimationSearchTextEntry:GetText() animationFrame.SearchString = text:lower() animationFrame.AnimationScrollBox:Refresh() end --build an index table to be used in the scroll selection function animationFrame.BuildAnimationDataForScroll() local db = Plater.db.profile.spell_animation_list local t = {} --get the player class and only show animations that is used on its class local _, playerClass = UnitClass ("player") for spellID, animationTable in pairs (db) do if (animationTable.info.class == playerClass) then tinsert (t, animationTable) end end animationFrame.AnimationScrollBox:SetData (t) animationFrame.AnimationScrollBox:Refresh() end --sort by name, index 5 holds the name:lower() function animationFrame.SortScroll (t1, t2) return t1[5] < t2[5] end --update the scroll list in the left side function animationFrame.RefreshAnimationSelectScrollBox (self, data, offset, total_lines) --animationFrame.SearchString local dataInOrder = {} if (animationFrame.SearchString ~= "") then for i = 1, #data do local animationTable = data[i] local spellID = animationTable.info.spellid local spellName, _, spellIcon = GetSpellInfo (spellID) if (spellName) then local spellNameLower = spellName:lower() if (spellNameLower:find (animationFrame.SearchString)) then dataInOrder [#dataInOrder+1] = {spellID, data[i], spellName, spellIcon, spellNameLower} end end end else for i = 1, #data do local animationTable = data[i] local spellID = animationTable.info.spellid local spellName, _, spellIcon = GetSpellInfo (spellID) if (spellName) then local spellNameLower = spellName:lower() dataInOrder [#dataInOrder+1] = {spellID, data[i], spellName, spellIcon, spellNameLower} end end end table.sort (dataInOrder, animationFrame.SortScroll) --update the scroll for i = 1, total_lines do local index = i + offset local t = dataInOrder [index] if (t) then --get the data local spellID = t[1] local data = t[2] local spellName = t[3] local spellIcon = t[4] --update the line local line = self:GetLine (i) line:UpdateLine (spellID, data, spellName, spellIcon) if (data == currentAnimation) then line:SetBackdropColor (unpack (scrollbox_line_backdrop_color_selected)) else line:SetBackdropColor (unpack (scrollbox_line_backdrop_color)) end end end end function animationFrame.OnEnterScrollSelectionLine (self) self:SetBackdropColor (.3, .3, .3, .6) end function animationFrame.OnLeaveScrollSelectionLine (self) --check if the hover overed button is the current animation being edited if (currentAnimation == self.Data) then self:SetBackdropColor (unpack (scrollbox_line_backdrop_color_selected)) else self:SetBackdropColor (unpack (scrollbox_line_backdrop_color)) end end function animationFrame.EditAnimation (spellID) local animationObject = animationFrame.GetAnimation (spellID) if (not animationObject) then Plater:Msg ("animation not found") return end currentAnimation = animationObject --refresh the spell selection box animationFrame.AnimationScrollBox:Refresh() --update the editing animation --animationFrame:HideAllConfigFrames() animationFrame.EffectSelectionDropdown:Refresh() animationFrame.EffectSelectionDropdown:Select (1, true) animationFrame.OnSelectEffect (_, _, 1) animationFrame.RefreshAddAnimationButtons() if (animationFrame.IsExporting or animationFrame.IsImporting) then animationFrame.HideStringField() end end --user selected 'paste' in the context menu of 'self' --copy the settings from the 'currentCopy' variable into the animation table for this widget function animationFrame.PasteAnimationSettings (self) if (not currentCopy or #currentCopy == 0) then Plater:Msg ("there's no animation to paste.") return end local spellID = self.SpellID if (spellID) then local animationObject = animationFrame.GetAnimation (spellID) if (animationObject) then --iterate among all copied animations for i = 1, #currentCopy do local thisCopiedEffect = currentCopy [i] local copiedEffectType = thisCopiedEffect.animation_type --below it iterates among all animation in the target animation object, if it doesn't find an effect table like the copied one, it needs to add it then local shouldAdd = true for i = 1, #animationObject do local animationEffect = animationObject [i] if (animationEffect.animation_type == copiedEffectType) then --replace the effect settings DF.table.copy (animationEffect, thisCopiedEffect) shouldAdd = false break end end --if it fails to find a similar effect, add it if (shouldAdd) then tinsert (animationObject, DF.table.copy ({}, thisCopiedEffect)) end end animationFrame.EditAnimation (spellID) Plater.RefreshDBUpvalues() Plater:Msg ("settings applied!") else Plater:Msg ("animation net found") end else Plater:Msg ("invalid spellID") end end function animationFrame.OnClickMenuLine (self, spellID, option, value) if (option == "editanimation") then animationFrame.EditAnimation (spellID) elseif (option == "copy") then local animationObject = animationFrame.GetAnimation (self.SpellID) --make a new table for the copied effects currentCopy = {} --animations stay in the indexed part of the animtion object --copy the settings of these indexes into the copy table for i = 1, #animationObject do local effect = animationObject [i] tinsert (currentCopy, DF.table.copy ({}, effect)) end local spellName = GetSpellInfo (spellID) if (spellName) then Plater:Msg (spellName .. " copied.") end elseif (option == "export") then animationFrame.ExportAnimation (self) elseif (option == "paste") then animationFrame.PasteAnimationSettings (self) elseif (option == "remove") then animationFrame.RemoveAnimation (self) elseif (option == "export_table") then animationFrame.ExportAnimation (self, true) end GameCooltip:Hide() end function animationFrame.OnClickScrollSelectionLine (self, button) local spellID = self.SpellID if (spellID) then if (button == "LeftButton") then animationFrame.EditAnimation (spellID) elseif (button == "RightButton") then --open menu GameCooltip:Preset (2) GameCooltip:SetType ("menu") GameCooltip:SetOption ("TextSize", 10) GameCooltip:SetOption ("FixedWidth", 200) GameCooltip:SetOption ("ButtonsYModSub", -1) GameCooltip:SetOption ("YSpacingModSub", -4) GameCooltip:SetOwner (self, "topleft", "topright", 2, 0) GameCooltip:SetFixedParameter (spellID) GameCooltip:AddLine ("Edit Animation") GameCooltip:AddMenu (1, animationFrame.OnClickMenuLine, "editanimation") GameCooltip:AddIcon ([[Interface\BUTTONS\UI-GuildButton-PublicNote-Up]], 1, 1, 16, 16) GameCooltip:AddLine ("Copy Settings") GameCooltip:AddMenu (1, animationFrame.OnClickMenuLine, "copy") GameCooltip:AddIcon ([[Interface\AddOns\Plater\images\icons]], 1, 1, 16, 16, 3/512, 21/512, 215/512, 233/512) if (currentCopy) then GameCooltip:AddLine ("Paste Settings") GameCooltip:AddMenu (1, animationFrame.OnClickMenuLine, "paste") GameCooltip:AddIcon ([[Interface\AddOns\Plater\images\icons]], 1, 1, 16, 16, 3/512, 21/512, 215/512, 233/512) else GameCooltip:AddLine ("Paste Settings", "", 1, "gray") GameCooltip:AddMenu (1, animationFrame.OnClickMenuLine, "paste") GameCooltip:AddIcon ([[Interface\AddOns\Plater\images\icons]], 1, 1, 16, 16, 3/512, 21/512, 215/512, 233/512, false, false, true) end GameCooltip:AddLine ("Export As a Text String", "", 1) GameCooltip:AddIcon ([[Interface\BUTTONS\UI-GuildButton-MOTD-Up]], 1, 1, 16, 16, 1, 0, 0, 1) GameCooltip:AddMenu (1, animationFrame.OnClickMenuLine, "export") GameCooltip:AddLine ("Remove") GameCooltip:AddMenu (1, animationFrame.OnClickMenuLine, "remove") GameCooltip:AddIcon ([[Interface\AddOns\Plater\images\icons]], 1, 1, 16, 16, 3/512, 21/512, 235/512, 257/512) --dev tool to export in database format if (GetRealmName() == "Azralon") then GameCooltip:AddLine ("$div") GameCooltip:AddLine ("Export To Table (dev)", "", 1) GameCooltip:AddIcon ([[Interface\BUTTONS\UI-GuildButton-MOTD-Up]], 1, 1, 16, 16, 1, 0, 0, 1) GameCooltip:AddMenu (1, animationFrame.OnClickMenuLine, "export_table") end GameCooltip:Show() end end end --update a single line in the scroll list function animationFrame.UpdateScrollLine (self, spellID, data, spellName, spellIcon) self.Icon:SetTexture (spellIcon) self.Icon:SetTexCoord (.1, .9, .1, .9) self.AnimationName:SetText (spellName) self.SpellID = spellID self.Data = data end function animationFrame:HideAllConfigFrames() for _, frame in pairs (animationFrame.AllConfigFrames) do frame:Hide() end end function animationFrame.OnSelectEffect (self, _, effectIndex) if (not currentAnimation [effectIndex]) then animationFrame.DisableOptions() return else animationFrame.EnableOptions() end animationFrame.CurrentIndex = effectIndex animationFrame:HideAllConfigFrames() local animationData = currentAnimation [animationFrame.CurrentIndex] local configFrame = animationFrame.AllConfigFrames [animationData.animation_type] configFrame.Data = animationData configFrame:RefreshOptions() configFrame:Show() end function animationFrame.RefreshEffectListDropdown (self) local t = {} if (currentAnimation) then for animationIndex, animationTable in ipairs (currentAnimation) do tinsert (t, {label = " #" .. animationIndex .. " " .. animationTable.animation_type, value = animationIndex, onclick = animationFrame.OnSelectEffect}) end end return t end function animationFrame.AddNewShakeEffect() if (currentAnimation) then tinsert (currentAnimation, { enabled = true, animation_type = "frameshake", scaleX = .1, scaleY = 1, absolute_sineX = false, absolute_sineY = false, duration = 0.1, amplitude = 3, frequency = 1, fade_in = 0.01, fade_out = 0.09, cooldown = 0.5, critical_scale = 1.05, }) animationFrame.EffectSelectionDropdown:Refresh() animationFrame.CurrentIndex = #currentAnimation animationFrame.EffectSelectionDropdown:Select (#currentAnimation, true) animationFrame.OnSelectEffect (_, _, #currentAnimation) animationFrame.RefreshAddAnimationButtons() end end function animationFrame.AddNewScaleEffect() if (currentAnimation) then tinsert (currentAnimation, { enabled = true, duration = 0.05, --seconds animation_type = "scale", cooldown = 0.75, --seconds scale_upX = 1.03, scale_upY = 1.03, scale_downX = 0.97, scale_downY = 0.97, }) animationFrame.EffectSelectionDropdown:Refresh() animationFrame.CurrentIndex = #currentAnimation animationFrame.EffectSelectionDropdown:Select (#currentAnimation, true) animationFrame.OnSelectEffect (_, _, #currentAnimation) animationFrame.RefreshAddAnimationButtons() end end function animationFrame.RefreshAddAnimationButtons() animationFrame.AddShakeButton:Enable() animationFrame.AddScaleButton:Enable() if (not currentAnimation) then animationFrame.AddShakeButton:Disable() animationFrame.AddScaleButton:Disable() return end for animationIndex, animationTable in ipairs (currentAnimation) do if (animationTable.animation_type == "scale") then animationFrame.AddScaleButton:Disable() end if (animationTable.animation_type == "frameshake") then animationFrame.AddShakeButton:Disable() end end end local cooltipInjectionScrollLine = function (self, fixed_parameter) GameCooltip:Preset (2) GameCooltip:SetOption ("TextSize", 10) GameCooltip:SetOption ("FixedWidth", 200) local animationObject = animationFrame.GetAnimation (self.SpellID) local lastEdited = date ("%d/%m/%Y", animationObject.info.time) local spellName, _, spellIcon = GetSpellInfo (self.SpellID) GameCooltip:AddLine (spellName, nil, 1, "yellow", "yellow", 11, "Friz Quadrata TT", "OUTLINE") GameCooltip:AddIcon (spellIcon, 1, 1, 18, 18, .1, .9, .1, .9) GameCooltip:AddLine ("Last Edited:", lastEdited) if (animationObject.info.desc and animationObject.info.desc ~= "") then GameCooltip:AddLine (animationObject.info.desc, "", 1, "gray") end end local cooltipInjectionTable_ScrollLine = { Type = "tooltip", BuildFunc = cooltipInjectionScrollLine, ShowSpeed = 0.016, MyAnchor = "topleft", HisAnchor = "topright", X = 10, Y = 0, } function animationFrame.RemoveAnimation (self) local spellID = self.SpellID if (spellID) then --is removing the animation which is currently being edited? if (currentAnimation == Plater.db.profile.spell_animation_list [spellID]) then animationFrame.DisableOptions() animationFrame.AddShakeButton:Disable() animationFrame.AddScaleButton:Disable() currentAnimation = nil animationFrame.EffectSelectionDropdown:Refresh() end Plater.db.profile.spell_animation_list [spellID] = nil Plater.RefreshDBUpvalues() animationFrame.BuildAnimationDataForScroll() end end function animationFrame.ImportAnimation() animationFrame.IsExporting = nil animationFrame.IsImporting = true animationFrame.ImportStringField:Show() animationFrame.AnimationConfigFrame:Hide() animationFrame.ImportStringField:SetText ("") animationFrame.ImportStringField:SetFocus (true) end function animationFrame.ExportDev (self) local spellID = self.SpellID local animationToExport = animationFrame.GetAnimation (spellID) local copy = DF.table.copy ({}, animationToExport) copy = { [spellID] = copy } local spellName = GetSpellInfo (spellID) local class = UnitClass ("player") animationFrame.ImportStringField:SetText ("--" .. spellName .. " (" .. class .. ")\n" .. DF.table.dump (copy)) animationFrame.ImportStringField:SetFocus (true) animationFrame.ImportStringField.editbox:HighlightText() animationFrame.AnimationConfigFrame:Hide() return end function animationFrame.ExportAnimation (self, isDev) animationFrame.IsExporting = true animationFrame.IsImporting = nil animationFrame.ImportStringField:Show() if (isDev) then animationFrame.ExportDev (self) return end local spellID = self.SpellID local animationToExport = animationFrame.GetAnimation (spellID) if (animationToExport) then --export to string animationFrame.ImportStringField:SetText (Plater.CompressData (animationToExport, "print") or "failed to export") C_Timer.After (.1, function() animationFrame.ImportStringField:SetFocus (true) animationFrame.ImportStringField.editbox:HighlightText() end) animationFrame.AnimationConfigFrame:Hide() end end function animationFrame.DoImportAnimation (animationObject) local spellID = animationObject.info.spellid local spellName = GetSpellInfo (spellID) local db = Plater.db.profile.spell_animation_list db [spellID] = animationObject Plater:Msg ("animation for spell " .. spellName .. " added!") local _, class = UnitClass ("player") if (class ~= animationObject.info.class) then Plater:Msg ("this animation is for " .. animationObject.info.class .. " and won't show on this character.") end animationFrame.EditAnimation (spellID) animationFrame.BuildAnimationDataForScroll() Plater.RefreshDBUpvalues() end function animationFrame.ConfirmImportAnimation() if (animationFrame.IsExporting) then animationFrame.HideStringField() return end local text = animationFrame.ImportStringField:GetText() local animationObject = Plater.DecompressData (text, "print") animationFrame.HideStringField() if (animationObject) then local db = Plater.db.profile.spell_animation_list local spellID = animationObject.info.spellid if (not spellID) then Plater:Msg ("invalid animation.") return end local spellName = GetSpellInfo (spellID) if (not spellName) then Plater:Msg ("the spell for this animation doesn't exists.") return end --already have if (db [spellID]) then --show a box to confirm DF:ShowPromptPanel ("Animation for " .. spellName .. " already exists, overwrite?", function() --true animationFrame.DoImportAnimation (animationObject) end, function() return end) else animationFrame.DoImportAnimation (animationObject) end else Plater:Msg ("invalid animation.") end end function animationFrame.HideStringField() animationFrame.IsExporting = nil animationFrame.IsImporting = nil animationFrame.ImportStringField:Hide() animationFrame.ImportStringField:SetText ("") animationFrame.AnimationConfigFrame:Show() end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ --> build the frames local optionsTable = { {type = "label", get = function() return "General Settings:" end, text_template = DF:GetTemplate ("font", "ORANGE_FONT_TEMPLATE")}, { type = "toggle", get = function() return Plater.db.profile.spell_animations end, set = function (self, fixedparam, value) Plater.db.profile.spell_animations = value Plater.RefreshDBUpvalues() end, name = "Spell Animations Enabled", desc = "If enabled some of your abilities will cause the nameplate to shake or play a special effect when the ability hits the enemy.\n\nCustomize each animation in the Animations tab.", }, { type = "range", get = function() return Plater.db.profile.spell_animations_scale end, set = function (self, fixedparam, value) Plater.db.profile.spell_animations_scale = value end, min = 0.75, max = 2.75, step = 0.1, name = "Overall Intensity", desc = "Overall intensity scale of the spell animations.", thumbscale = 1.8, usedecimals = true, }, } DF:BuildMenu (animationFrame, optionsTable, 10, startYGeneralSettings, 330, true, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template, animationFrame.OnDataChange) local scrollBoxHeight = 396 - 70 --dropdown select spell to add local buildAddSpellOptions = function() local t = {} local db = Plater.db.profile.spell_animation_list for spellID, spellInfo in pairs (CLEUFrame.SpellCaptured) do if (not db [spellInfo.ID]) then local _, _, spellIcon = GetSpellInfo (spellInfo.ID) if (spellIcon) then tinsert (t, {label = spellInfo.Name, value = spellInfo.ID, onclick = function()end, desc = "Spell ID: " .. spellInfo.ID, icon = spellIcon, texcoord = {.1, .9, .1, .9}}) end end end return t end local selectSpellLabel = DF:CreateLabel (animationFrame, "Select Spell to Add Animation:", DF:GetTemplate ("font", "ORANGE_FONT_TEMPLATE")) local selectSpellDropdown = DF:CreateDropDown (animationFrame, buildAddSpellOptions, 1, 130, 20, "SelectSpellDropdown", _, DF:GetTemplate ("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")) selectSpellDropdown:SetPoint ("topleft", selectSpellLabel, "bottomleft", 0, -2) --button add spell local addSpellButton = DF:CreateButton (animationFrame, animationFrame.AddNewAnimation, 40, 20, "Add", -1, nil, nil, nil, nil, nil, DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate ("font", "PLATER_BUTTON")) addSpellButton:SetPoint ("left", selectSpellDropdown, "right", 2, 0) addSpellButton.tooltip = function() if (not next (CLEUFrame.SpellCaptured)) then return "No spells to add?\n\nHit any npc with spells while this window is open to fill the dropdown with options." else return "Add animation for the selected spell." end end --button import animation local importButton = DF:CreateButton (animationFrame, animationFrame.ShowImportTextField, 26, 20, "", -1, nil, nil, nil, nil, nil, DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate ("font", "PLATER_BUTTON")) importButton:SetIcon ([[Interface\AddOns\Plater\images\icons]], 16, 16, "overlay", {5/512, 19/512, 195/512, 210/512}, {1, .8, .2}, nil, nil, nil, false) importButton:SetPoint ("left", addSpellButton, "right", 2, 0) importButton:HookScript ("OnEnter", function() GameCooltip:Preset (2) GameCooltip:SetOption ("TextSize", 10) GameCooltip:SetOption ("FixedWidth", 200) GameCooltip:SetOwner (importButton.widget) GameCooltip:AddLine ("Import Animation", "", 1, "yellow", "yellow", 12, nil, "OUTLINE") GameCooltip:AddLine ("Add an animation from a string.\n\nYou can export to string by right clicking an animation in the menu below.") GameCooltip:Show() end) importButton:HookScript ("OnLeave", function() GameCooltip:Hide() end) --search box local searchLabel = DF:CreateLabel (animationFrame, "Search:", DF:GetTemplate ("font", "ORANGE_FONT_TEMPLATE")) searchLabel:SetPoint ("topleft", selectSpellDropdown, "bottomleft", 0, -5) local searchAnimationTextEntry = DF:CreateTextEntry (animationFrame, function()end, 200, 20, "AnimationSearchTextEntry", _, _, options_dropdown_template) searchAnimationTextEntry:SetHook ("OnChar", animationFrame.OnSearchBoxTextChanged) searchAnimationTextEntry:SetHook ("OnTextChanged", animationFrame.OnSearchBoxTextChanged) searchAnimationTextEntry:SetPoint ("topleft", searchLabel, "bottomleft", 0, -2) --scrollbox to select the spell animation to edit local spellLabel = DF:CreateLabel (animationFrame, "Spell Animations", DF:GetTemplate ("font", "ORANGE_FONT_TEMPLATE")) spellLabel:SetPoint ("topleft", searchAnimationTextEntry, "bottomleft", 0, -5) local animationSelectScrollBox = DF:CreateScrollBox (animationFrame, "$parentScrollBox", animationFrame.RefreshAnimationSelectScrollBox, {}, 200, scrollBoxHeight, scrollbox_lines, scrollbox_line_height) animationSelectScrollBox:SetPoint ("topleft", spellLabel.widget, "bottomleft", 0, -2) DF:ReskinSlider (animationSelectScrollBox) animationFrame.AnimationScrollBox = animationSelectScrollBox local createNewLineFunc = function (self, index) --create a new line local line = CreateFrame ("button", "$parentLine" .. index, self, BackdropTemplateMixin and "BackdropTemplate") --set its parameters line:SetPoint ("topleft", self, "topleft", 1, -((index-1) * (scrollbox_line_height+1)) - 1) line:SetSize (scrollbox_size[1]-2, scrollbox_line_height) line:RegisterForClicks ("LeftButtonDown", "RightButtonDown") line:SetScript ("OnEnter", animationFrame.OnEnterScrollSelectionLine) line:SetScript ("OnLeave", animationFrame.OnLeaveScrollSelectionLine) line:SetScript ("OnClick", animationFrame.OnClickScrollSelectionLine) line.CoolTip = cooltipInjectionTable_ScrollLine GameCooltip:CoolTipInject (line) line:SetBackdrop ({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true, edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1}) line:SetBackdropColor (unpack (scrollbox_line_backdrop_color)) line:SetBackdropBorderColor (0, 0, 0, 1) local icon = line:CreateTexture ("$parentIcon", "overlay") icon:SetSize (scrollbox_line_height-4, scrollbox_line_height-4) local animationName = DF:CreateLabel (line, "", DF:GetTemplate ("font", "PLATER_SCRIPTS_NAME")) --setup anchors icon:SetPoint ("left", line, "left", 2, 0) animationName:SetPoint ("topleft", icon, "topright", 2, -2) line.Icon = icon line.AnimationName = animationName line.UpdateLine = animationFrame.UpdateScrollLine return line end --create the scrollbox lines for i = 1, scrollbox_lines do animationSelectScrollBox:CreateLine (createNewLineFunc) end --import box --text editor local luaeditor_backdrop_color = {.2, .2, .2, .5} local luaeditor_border_color = {0, 0, 0, 1} local edit_script_size = {620, 431} local buttons_size = {120, 20} local importStringField = DF:NewSpecialLuaEditorEntry (animationFrame, 825, edit_script_size[2] - 75, "ImportEditor", "$parentImportEditor", true) importStringField:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) importStringField:SetBackdropBorderColor (unpack (luaeditor_border_color)) importStringField:SetBackdropColor (unpack (luaeditor_backdrop_color)) importStringField:Hide() animationFrame.ImportStringField = importStringField DF:ReskinSlider (importStringField.scroll) --import button local okayButton = DF:CreateButton (importStringField, animationFrame.ConfirmImportAnimation, buttons_size[1], buttons_size[2], "Okay", -1, nil, nil, nil, nil, nil, DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate ("font", "PLATER_BUTTON")) okayButton:SetIcon ([[Interface\BUTTONS\UI-Panel-BiggerButton-Up]], 20, 20, "overlay", {0.1, .9, 0.1, .9}) --cancel button local cancelButton = DF:CreateButton (importStringField, animationFrame.HideStringField, buttons_size[1], buttons_size[2], "Cancel", -1, nil, nil, nil, nil, nil, DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate ("font", "PLATER_BUTTON")) cancelButton:SetIcon ([[Interface\BUTTONS\UI-Panel-MinimizeButton-Up]], 20, 20, "overlay", {0.1, .9, 0.1, .9}) okayButton:SetPoint ("topright", importStringField, "bottomright", 0, -7) cancelButton:SetPoint ("right", okayButton, "left", -20, 0) --editing settings of the animation local animationConfigFrame = CreateFrame ("frame", "$parentAnimationConfig", animationFrame, BackdropTemplateMixin and "BackdropTemplate") DF:ApplyStandardBackdrop (animationConfigFrame) animationConfigFrame:SetPoint ("topleft", animationSelectScrollBox, "topright", 45, 53 + 70) animationConfigFrame:SetSize (825, scrollBoxHeight + 53 + 5) animationFrame.AnimationConfigFrame = animationConfigFrame local animationPreviewFrame = CreateFrame ("frame", "$parentPreviewConfig", animationFrame, BackdropTemplateMixin and "BackdropTemplate") DF:ApplyStandardBackdrop (animationPreviewFrame) animationPreviewFrame:SetPoint ("topleft", animationConfigFrame, "bottomleft", 0, -5) animationPreviewFrame:SetPoint ("topright", animationConfigFrame, "bottomright", 0, -5) animationPreviewFrame:SetHeight (60) animationFrame.AnimationPreviewFrame = animationPreviewFrame local previewHeaderLabel = DF:CreateLabel (animationPreviewFrame, "Preview Settings:", DF:GetTemplate ("font", "ORANGE_FONT_TEMPLATE")) previewHeaderLabel:SetPoint ("topleft", animationPreviewFrame, "topleft", 5, -5) --select effect dropdown (scale, shake) local effectSelectionLabel = DF:CreateLabel (animationConfigFrame, "Effect:", DF:GetTemplate ("font", "ORANGE_FONT_TEMPLATE")) local effectSelectionDropdown = DF:CreateDropDown (animationConfigFrame, animationFrame.RefreshEffectListDropdown, 1, 160, 20, "EffectSelectionDropdown", _, DF:GetTemplate ("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")) effectSelectionDropdown:SetPoint ("left", effectSelectionLabel, "right", 2, 0) animationFrame.EffectSelectionDropdown = effectSelectionDropdown --add shake effect local addShakeButton = DF:CreateButton (animationConfigFrame, animationFrame.AddNewShakeEffect, 120, 20, "Add Shake Effect", -1, nil, nil, nil, nil, nil, DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate ("font", "PLATER_BUTTON")) animationFrame.AddShakeButton = addShakeButton --add scale effect local addScaleButton = DF:CreateButton (animationConfigFrame, animationFrame.AddNewScaleEffect, 120, 20, "Add Scale Effect", -1, nil, nil, nil, nil, nil, DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate ("font", "PLATER_BUTTON")) addScaleButton:SetPoint ("left", addShakeButton, "right", 2, 0) animationFrame.AddScaleButton = addScaleButton animationFrame.AllConfigFrames = {} local scaleOptionsFrame = CreateFrame ("frame", "$parentScaleFrame", animationConfigFrame, BackdropTemplateMixin and "BackdropTemplate") scaleOptionsFrame:Hide() animationFrame.AllConfigFrames ["scale"] = scaleOptionsFrame local shakeOptionsFrame = CreateFrame ("frame", "$parentShakeFrame", animationConfigFrame, BackdropTemplateMixin and "BackdropTemplate") animationFrame.AllConfigFrames ["frameshake"] = shakeOptionsFrame function animationFrame.DisableOptions() for _, widget in ipairs (scaleOptionsFrame.widget_list) do if (widget.Disable) then widget:Disable() end end for _, widget in ipairs (shakeOptionsFrame.widget_list) do if (widget.Disable) then widget:Disable() end end end function animationFrame.EnableOptions() for _, widget in ipairs (scaleOptionsFrame.widget_list) do if (widget.Enable) then widget:Enable() end end for _, widget in ipairs (shakeOptionsFrame.widget_list) do if (widget.Enable) then widget:Enable() end end end for _, frame in pairs (animationFrame.AllConfigFrames) do frame:SetSize (460, 250) frame:SetPoint ("topleft", animationConfigFrame, "topleft", 5, -5) --frame:Hide() frame.Data = {} end local scaleOptionsTable = { { type = "toggle", get = function() return scaleOptionsFrame.Data.enabled end, set = function (self, fixedparam, value) scaleOptionsFrame.Data.enabled = value end, name = "Enabled", }, {type = "blank"}, { type = "range", get = function() return scaleOptionsFrame.Data.duration end, set = function (self, fixedparam, value) scaleOptionsFrame.Data.duration = value end, min = 0.05, max = 1, step = 0.05, usedecimals = true, name = "Duration", }, {type = "blank"}, { type = "range", get = function() return scaleOptionsFrame.Data.scale_upX end, set = function (self, fixedparam, value) scaleOptionsFrame.Data.scale_upX = value end, min = 0, max = 20, step = 0.05, usedecimals = true, name = "Scale Up X", }, { type = "range", get = function() return scaleOptionsFrame.Data.scale_upY end, set = function (self, fixedparam, value) scaleOptionsFrame.Data.scale_upY = value end, min = 0, max = 20, step = 0.05, usedecimals = true, name = "Scale Up Y", }, { type = "range", get = function() return scaleOptionsFrame.Data.scale_downX end, set = function (self, fixedparam, value) scaleOptionsFrame.Data.scale_downX = value end, min = 0, max = 20, step = 0.05, usedecimals = true, name = "Scale Down X", }, { type = "range", get = function() return scaleOptionsFrame.Data.scale_downY end, set = function (self, fixedparam, value) scaleOptionsFrame.Data.scale_downY = value end, min = 0, max = 20, step = 0.05, usedecimals = true, name = "Scale Down Y", }, {type = "blank"}, { type = "range", get = function() return scaleOptionsFrame.Data.cooldown end, set = function (self, fixedparam, value) scaleOptionsFrame.Data.cooldown = value end, min = 0, max = 20, step = 0.05, usedecimals = true, name = "Cooldown", }, {type = "blank"}, { type = "range", get = function() return scaleOptionsFrame.Data.critical_scale end, set = function (self, fixedparam, value) scaleOptionsFrame.Data.critical_scale = value end, min = 1, max = 2, step = 0.05, usedecimals = true, name = "Critical Hit Scale", }, } local shakeOptionsTable = { { type = "toggle", get = function() return shakeOptionsFrame.Data.enabled end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.enabled = value end, name = "Enabled", }, {type = "blank"}, { type = "range", get = function() return shakeOptionsFrame.Data.duration end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.duration = value end, min = 0.05, max = 1, step = 0.05, usedecimals = true, name = "Duration", desc = "Animation duration time.", }, { type = "range", get = function() return shakeOptionsFrame.Data.amplitude end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.amplitude = value end, min = 0, max = 50, step = 0.05, usedecimals = true, name = "Amplitude", desc = "Scale the strength of the animation.", }, { type = "range", get = function() return shakeOptionsFrame.Data.frequency end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.frequency = value end, min = 0, max = 200, step = 0.05, usedecimals = true, name = "Frequency", desc = "Scale how fast and often the animation plays within its duration time.", }, {type = "blank"}, { type = "range", get = function() return shakeOptionsFrame.Data.scaleX end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.scaleX = value end, min = -50, max = 50, step = 0.05, usedecimals = true, name = "Scale X", desc = "Scale the animation on its horizontal axis.", }, { type = "range", get = function() return shakeOptionsFrame.Data.scaleY end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.scaleY = value end, min = -50, max = 50, step = 0.05, usedecimals = true, name = "Scale Y", desc = "Scale the animation on its vertical axis.", }, { type = "toggle", get = function() return shakeOptionsFrame.Data.absolute_sineX end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.absolute_sineX = value end, name = "Absolute Sine X", desc = "Makes the sine wave of the animation to not use its negative part making it always to the right side.\n\nIf the |cFFFFFF00Scale X|r option has a negative value the animation goes to the left side.", }, { type = "toggle", get = function() return shakeOptionsFrame.Data.absolute_sineY end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.absolute_sineY = value end, name = "Absolute Sine Y", desc = "Makes the sine wave of the animation to not use its negative part making it always to go up.\n\nIf the |cFFFFFF00Scale Y|r option has a negative value the animation goes down instead.", }, {type = "blank"}, { type = "range", get = function() return shakeOptionsFrame.Data.fade_in end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.fade_in = value end, min = 0, max = 2, step = 0.05, usedecimals = true, name = "Fade In Time", desc = "Time the animation takes to go from not playing at all to its full effect strength.\n\nThis time is within the animation duration time.", }, { type = "range", get = function() return shakeOptionsFrame.Data.fade_out end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.fade_out = value end, min = 0, max = 2, step = 0.05, usedecimals = true, name = "Fade Out Time", desc = "Time the animation takes to go from playing its full effect to not playing at all.\n\nThis time is within the animation duration time.", }, {type = "blank"}, { type = "range", get = function() return shakeOptionsFrame.Data.cooldown end, set = function (self, fixedparam, value) shakeOptionsFrame.Data.cooldown = value end, min = 0, max = 20, step = 0.05, usedecimals = true, name = "Cooldown", desc = "Won't play this animation again while its cooldown time isn't passed.", }, {type = "blank"}, { type = "range", get = function() return scaleOptionsFrame.Data.critical_scale end, set = function (self, fixedparam, value) scaleOptionsFrame.Data.critical_scale = value end, min = 1, max = 2, step = 0.05, usedecimals = true, name = "Critical Hit Scale", }, } --the callback function seems to be firing before the OnValueChanged function in the widget --delaying the update a little bit fixes this local updateAnimationOnPlater = function() Plater.RefreshDBLists() --invalidate the timer animationFrame.RefreshTimer:Cancel() end function animationFrame.OnDataChange() if (animationFrame.RefreshTimer) then if (not animationFrame.RefreshTimer._cancelled) then return end end animationFrame.RefreshTimer = C_Timer.NewTimer (.1, updateAnimationOnPlater) end DF:BuildMenu (scaleOptionsFrame, scaleOptionsTable, 0, 0, 330, true, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template, animationFrame.OnDataChange) DF:BuildMenu (shakeOptionsFrame, shakeOptionsTable, 0, 0, 330, true, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template, animationFrame.OnDataChange) local animationPreviewOptionsTable = { { type = "toggle", get = function() return previewEnabled end, set = function (self, fixedparam, value) previewEnabled = value animationFrame.UpdatePreview() end, name = "Enabled", }, { type = "range", get = function() return previewLoopTime end, set = function (self, fixedparam, value) animationFrame.UpdatePreview (value) end, min = .1, max = 10, step = 0.05, usedecimals = true, name = "Loop Time", }, } DF:BuildMenu (animationPreviewFrame, animationPreviewOptionsTable, 5, -25, 10, true, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template, animationFrame.OnDataChange) animationFrame.DisableOptions() selectSpellLabel:SetPoint ("topleft", animationFrame, "topleft", startX, startY) effectSelectionLabel:SetPoint ("bottomleft", animationConfigFrame, "topleft", 0, 8) addShakeButton:SetPoint ("left", effectSelectionDropdown, "right", 2, 0) importStringField:SetPoint ("topleft", animationSelectScrollBox, "topright", 45, 53 + 70) animationFrame.RefreshAddAnimationButtons() animationFrame.BuildAnimationDataForScroll() end -- endd doo thend thens ends elses