diff --git a/Libs/DF/addon.examples.lua b/Libs/DF/addon.examples.lua new file mode 100644 index 00000000..47d1cc04 --- /dev/null +++ b/Libs/DF/addon.examples.lua @@ -0,0 +1,53 @@ + +--[=[ +for this example, let's consider the name of your addon is "Slice And Dance" +addon folder name on World of Warcraft/_retail_/Interface/AddOns/SliceAndDance/ +toc file example /World of Warcraft/_retail_/Interface/AddOns/SliceAndDance/SliceAndDance.toc: + ## Interface: 100107 + ## Title: "Slice And Dance" + ## Notes: Show a slice and dice bar for rogues + ## SavedVariables: SliceAndDanceDatabase + SliceAndDance_Core.lua +--]=] + +--create a new file on your addon folder called "SliceAndDance_Core.lua" +--this are the contents to add to the file + +--each file of your addon receives a payload with the addon name and a private table +--this private table is shared between all files of your addon and cannot be accessed by other addons or scripts +--the addon name is the ToC name of your addon, the toc is also the folder name of your addon in the addons folder +local addonName, priviteTable = ... + +--saved variables name +--this is the name of the global table where your addon will store it's saved variables +--you define this on the addon.toc file under the line "## SavedVariables: SliceAndDanceDatabase" +local savedVariablesName = "SliceAndDanceDatabase" + +--default settings +--a simple table with default settings for your addon, any value modified by the user will be stored in the saved variables table +--if your addon doesn't have any settings, you can just pass an empty table +local defaultSettingsExample = { + width = 500, + height = 500, + name = "John", +} + +local detailsFramework = DetailsFramework +--create the core addon object, this is a table which will all public functions of your addon +local myNewAddonObject = detailsFramework:CreateNewAddOn(addonName, savedVariablesName, defaultSettingsExample) + +--by default, the table generated by the CreateNewAddOn() isn't placed in the global environment +--if this is desired for some reason, you can do it manually +_G.MyNewAddon = myNewAddonObject + +--this function is called when the savedVariables of your addon is ready to be used +function myNewAddonObject.OnLoad(self, profile) + --self is: myNewAddonObject + --profile is a table with defaultSettingsExample +end + +--this function is called when when the loading screen is done and the player character is ready to play +function myNewAddonObject.OnInit(self, profile) --fired from detailsFramework at PLAYER_LOGIN + --self is: myNewAddonObject + --profile is a table with defaultSettingsExample +end \ No newline at end of file diff --git a/Libs/DF/addon.lua b/Libs/DF/addon.lua index 8285d6dc..d41e7ec2 100644 --- a/Libs/DF/addon.lua +++ b/Libs/DF/addon.lua @@ -119,7 +119,7 @@ function detailsFramework:CreateNewAddOn(addonName, globalSavedVariablesName, sa end ---old create addon +--old create addon using ace3 function detailsFramework:CreateAddOn(name, global_saved, global_table, options_table, broker) local addon = LibStub("AceAddon-3.0"):NewAddon (name, "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "DetailsFramework-1.0", "AceComm-3.0") diff --git a/Libs/DF/auras.lua b/Libs/DF/auras.lua index fc01800d..be234a20 100644 --- a/Libs/DF/auras.lua +++ b/Libs/DF/auras.lua @@ -1,26 +1,30 @@ +---@type detailsframework local DF = _G ["DetailsFramework"] if (not DF or not DetailsFrameworkCanLoad) then - return + return end +local detailsFramework = DF + local _ -local tinsert = tinsert +local tinsert = table.insert local GetSpellInfo = GetSpellInfo local lower = string.lower local GetSpellBookItemInfo = GetSpellBookItemInfo +local unpack = unpack -local CONST_MAX_SPELLS = 450000 +local CONST_MAX_SPELLS = 500000 -function DF:GetAuraByName (unit, spellName, isDebuff) +function DF:GetAuraByName(unit, spellName, isDebuff) isDebuff = isDebuff and "HARMFUL|PLAYER" for i = 1, 40 do - local name, texture, count, debuffType, duration, expirationTime, caster, canStealOrPurge, nameplateShowPersonal, spellId, canApplyAura, isBossDebuff, isCastByPlayer, nameplateShowAll = UnitAura (unit, i, isDebuff) + local name, texture, count, debuffType, duration, expirationTime, caster, canStealOrPurge, nameplateShowPersonal, spellId, canApplyAura, isBossDebuff, isCastByPlayer, nameplateShowAll = UnitAura(unit, i, isDebuff) if (not name) then return end - + if (name == spellName) then return name, texture, count, debuffType, duration, expirationTime, caster, canStealOrPurge, nameplateShowPersonal, spellId, canApplyAura, isBossDebuff, isCastByPlayer, nameplateShowAll end @@ -28,27 +32,25 @@ function DF:GetAuraByName (unit, spellName, isDebuff) end local default_text_for_aura_frame = { - AUTOMATIC = "Automatic", - MANUAL = "Manual", - METHOD = "Aura Tracking Method:", + AUTOMATIC = "Automatic", + MANUAL = "Manual", + METHOD = "Aura Tracking Method:", BUFFS_IGNORED = "Buffs Ignored", DEBUFFS_IGNORED = "Debuffs Ignored", BUFFS_TRACKED = "Buffs Tracked", DEBUFFS_TRACKED = "Debuffs Tracked", - + AUTOMATIC_DESC = "Auras are being tracked automatically, the addon controls what to show.\nYou may add auras to the blacklist or add extra auras to track.", MANUAL_DESC = "Auras are being tracked manually, the addon only check for auras you entered below.", - + MANUAL_ADD_BLACKLIST_BUFF = "Add Buff to Blacklist", MANUAL_ADD_BLACKLIST_DEBUFF = "Add Debuff to Blacklist", MANUAL_ADD_TRACKLIST_BUFF = "Add Buff to Tracklist", MANUAL_ADD_TRACKLIST_DEBUFF = "Add Debuff to Tracklist", } -function DF:LoadAllSpells (hashMap, indexTable, allSpellsSameName) - +function DF:LoadAllSpells(hashMap, indexTable, allSpellsSameName) --pre checking which tables to fill to avoid checking if the table exists during the gigantic loop for performance - if (not DF.LoadingAuraAlertFrame) then DF.LoadingAuraAlertFrame = CreateFrame("frame", "DetailsFrameworkLoadingAurasAlert", UIParent, "BackdropTemplate") DF.LoadingAuraAlertFrame:SetSize(340, 75) @@ -56,46 +58,46 @@ function DF:LoadAllSpells (hashMap, indexTable, allSpellsSameName) DF.LoadingAuraAlertFrame:SetFrameStrata("TOOLTIP") DF:ApplyStandardBackdrop(DF.LoadingAuraAlertFrame) DF.LoadingAuraAlertFrame:SetBackdropBorderColor(1, 0.8, 0.1) - + DF.LoadingAuraAlertFrame.IsLoadingLabel1 = DF:CreateLabel(DF.LoadingAuraAlertFrame, "We are currently loading spell names and spell IDs") DF.LoadingAuraAlertFrame.IsLoadingLabel2 = DF:CreateLabel(DF.LoadingAuraAlertFrame, "This may take only a few seconds") DF.LoadingAuraAlertFrame.IsLoadingImage1 = DF:CreateImage(DF.LoadingAuraAlertFrame, [[Interface\DialogFrame\UI-Dialog-Icon-AlertOther]], 32, 32) DF.LoadingAuraAlertFrame.IsLoadingLabel1.align = "center" DF.LoadingAuraAlertFrame.IsLoadingLabel2.align = "center" - + DF.LoadingAuraAlertFrame.IsLoadingLabel1:SetPoint("center", 16, 10) DF.LoadingAuraAlertFrame.IsLoadingLabel2:SetPoint("center", 16, -5) DF.LoadingAuraAlertFrame.IsLoadingImage1:SetPoint("left", 10, 0) end DF.LoadingAuraAlertFrame:Show() - + C_Timer.After(0, function() if (hashMap and not indexTable) then for i = 1, CONST_MAX_SPELLS do local spellName = GetSpellInfo(i) if (spellName) then - hashMap [lower (spellName)] = i + hashMap [lower(spellName)] = i end end - + elseif (not hashMap and indexTable) then for i = 1, CONST_MAX_SPELLS do local spellName = GetSpellInfo(i) if (spellName) then - indexTable [#indexTable+1] = lower (spellName) + indexTable [#indexTable+1] = lower(spellName) end end - + elseif (hashMap and indexTable) then if (allSpellsSameName) then for i = 1, CONST_MAX_SPELLS do local spellName = GetSpellInfo(i) if (spellName) then - spellName = lower (spellName) + spellName = lower(spellName) indexTable [#indexTable + 1] = spellName hashMap [spellName] = i - + --same name table local sameNameTable = allSpellsSameName [spellName] if (not sameNameTable) then @@ -109,21 +111,19 @@ function DF:LoadAllSpells (hashMap, indexTable, allSpellsSameName) for i = 1, CONST_MAX_SPELLS do local spellName = GetSpellInfo(i) if (spellName) then - spellName = lower (spellName) + spellName = lower(spellName) indexTable [#indexTable + 1] = spellName hashMap [spellName] = i end end end end - + DF.LoadingAuraAlertFrame:Hide() end) end -local cleanfunction = function() end - do local metaPrototype = { WidgetType = "aura_tracker", @@ -135,7 +135,7 @@ do --get the already existing metaPrototype local oldMetaPrototype = _G[DF.GlobalWidgetControlNames["aura_tracker"]] --check if is older - if ( (not oldMetaPrototype.dversion) or (oldMetaPrototype.dversion < DF.dversion) ) then + if ((not oldMetaPrototype.dversion) or(oldMetaPrototype.dversion < DF.dversion) ) then --the version is older them the currently loading one --copy the new values into the old metatable for funcName, _ in pairs(metaPrototype) do @@ -157,35 +157,35 @@ local on_profile_changed = function(self, newdb) self.db = newdb --automatic - self.buff_ignored:DoSetData (newdb.aura_tracker.buff_banned) - self.debuff_ignored:DoSetData (newdb.aura_tracker.debuff_banned) - self.buff_tracked:DoSetData (newdb.aura_tracker.buff_tracked) - self.debuff_tracked:DoSetData (newdb.aura_tracker.debuff_tracked) - + self.buff_ignored:DoSetData(newdb.aura_tracker.buff_banned) + self.debuff_ignored:DoSetData(newdb.aura_tracker.debuff_banned) + self.buff_tracked:DoSetData(newdb.aura_tracker.buff_tracked) + self.debuff_tracked:DoSetData(newdb.aura_tracker.debuff_tracked) + self.buff_ignored:DoRefresh() self.debuff_ignored:DoRefresh() self.buff_tracked:DoRefresh() self.debuff_tracked:DoRefresh() - + --manual - self.buffs_added:SetData (newdb.aura_tracker.buff) - self.debuffs_added:SetData (newdb.aura_tracker.debuff) + self.buffs_added:SetData(newdb.aura_tracker.buff) + self.debuffs_added:SetData(newdb.aura_tracker.debuff) self.buffs_added:Refresh() self.debuffs_added:Refresh() - + --method if (newdb.aura_tracker.track_method == 0x1) then self.f_auto:Show() self.f_manual:Hide() - + self.AutomaticTrackingCheckbox:SetValue(true) self.ManualTrackingCheckbox:SetValue(false) self.desc_label.text = self.LocTexts.AUTOMATIC_DESC - + elseif (newdb.aura_tracker.track_method == 0x2) then self.f_auto:Hide() self.f_manual:Show() - + self.AutomaticTrackingCheckbox:SetValue(false) self.ManualTrackingCheckbox:SetValue(true) self.desc_label.text = self.LocTexts.MANUAL_DESC @@ -193,187 +193,184 @@ local on_profile_changed = function(self, newdb) end local aura_panel_defaultoptions = { - height = 400, + height = 400, row_height = 18, width = 230, button_text_template = "OPTIONS_FONT_TEMPLATE" } -function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, texts) - +function DF:CreateAuraConfigPanel(parent, name, db, changeCallback, options, texts) 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 f = CreateFrame("frame", name, parent, "BackdropTemplate") - f.db = db - f.OnProfileChanged = on_profile_changed - f.LocTexts = texts + + local newAuraPanel = CreateFrame("frame", name, parent, "BackdropTemplate") + newAuraPanel.db = db + newAuraPanel.OnProfileChanged = on_profile_changed + newAuraPanel.LocTexts = texts options = options or {} self.table.deploy(options, aura_panel_defaultoptions) - - local f_auto = CreateFrame("frame", "$parent_Automatic", f, "BackdropTemplate") - local f_manual = CreateFrame("frame", "$parent_Manual", f, "BackdropTemplate") - f_auto:SetPoint("topleft", f, "topleft", 0, -24) - f_manual:SetPoint("topleft", f, "topleft", 0, -24) - f_auto:SetSize(600, 600) - f_manual:SetSize(600, 600) - f.f_auto = f_auto - f.f_manual = f_manual - + + local auraPanel_Auto = CreateFrame("frame", "$parent_Automatic", newAuraPanel, "BackdropTemplate") + local auraPanel_Manual = CreateFrame("frame", "$parent_Manual", newAuraPanel, "BackdropTemplate") + auraPanel_Auto:SetPoint("topleft", newAuraPanel, "topleft", 0, -24) + auraPanel_Manual:SetPoint("topleft", newAuraPanel, "topleft", 0, -24) + auraPanel_Auto:SetSize(600, 600) + auraPanel_Manual:SetSize(600, 600) + newAuraPanel.f_auto = auraPanel_Auto + newAuraPanel.f_manual = auraPanel_Manual + --check if the texts table is valid and also deploy default values into the table in case some value is nil texts = (type(texts == "table") and texts) or default_text_for_aura_frame DF.table.deploy(texts, default_text_for_aura_frame) - - ------------- - + local on_switch_tracking_method = function(self) local method = self.Method - - f.db.aura_tracker.track_method = method - if (change_callback) then - DF:QuickDispatch(change_callback) + + newAuraPanel.db.aura_tracker.track_method = method + if (changeCallback) then + DF:QuickDispatch(changeCallback) end if (method == 0x1) then - f_auto:Show() - f_manual:Hide() - f.AutomaticTrackingCheckbox:SetValue(true) - f.ManualTrackingCheckbox:SetValue(false) - f.desc_label.text = texts.AUTOMATIC_DESC - + auraPanel_Auto:Show() + auraPanel_Manual:Hide() + newAuraPanel.AutomaticTrackingCheckbox:SetValue(true) + newAuraPanel.ManualTrackingCheckbox:SetValue(false) + newAuraPanel.desc_label.text = texts.AUTOMATIC_DESC + elseif (method == 0x2) then - f_auto:Hide() - f_manual:Show() - f.AutomaticTrackingCheckbox:SetValue(false) - f.ManualTrackingCheckbox:SetValue(true) - f.desc_label.text = texts.MANUAL_DESC + auraPanel_Auto:Hide() + auraPanel_Manual:Show() + newAuraPanel.AutomaticTrackingCheckbox:SetValue(false) + newAuraPanel.ManualTrackingCheckbox:SetValue(true) + newAuraPanel.desc_label.text = texts.MANUAL_DESC end end - - local background_method_selection = CreateFrame("frame", nil, f, "BackdropTemplate") + + local background_method_selection = CreateFrame("frame", nil, newAuraPanel, "BackdropTemplate") background_method_selection:SetHeight(82) - background_method_selection:SetPoint("topleft", f, "topleft", 0, 0) - background_method_selection:SetPoint("topright", f, "topright", 0, 0) + background_method_selection:SetPoint("topleft", newAuraPanel, "topleft", 0, 0) + background_method_selection:SetPoint("topright", newAuraPanel, "topright", 0, 0) DF:ApplyStandardBackdrop(background_method_selection) - + local tracking_method_label = self:CreateLabel(background_method_selection, texts.METHOD, 12, "orange") tracking_method_label:SetPoint("topleft", background_method_selection, "topleft", 6, -4) - f.desc_label = self:CreateLabel(background_method_selection, "", 10, "silver") - f.desc_label:SetPoint("left", background_method_selection, "left", 130, 0) - f.desc_label:SetJustifyV ("top") - - local automatic_tracking_checkbox = DF:CreateSwitch(background_method_selection, on_switch_tracking_method, f.db.aura_tracker.track_method == 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, DF:GetTemplate("switch", "OPTIONS_CHECKBOX_BRIGHT_TEMPLATE")) + newAuraPanel.desc_label = self:CreateLabel(background_method_selection, "", 10, "silver") + newAuraPanel.desc_label:SetPoint("left", background_method_selection, "left", 130, 0) + newAuraPanel.desc_label:SetJustifyV("top") + + local automatic_tracking_checkbox = DF:CreateSwitch(background_method_selection, on_switch_tracking_method, newAuraPanel.db.aura_tracker.track_method == 0x1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, DF:GetTemplate("switch", "OPTIONS_CHECKBOX_BRIGHT_TEMPLATE")) automatic_tracking_checkbox.Method = 0x1 automatic_tracking_checkbox:SetAsCheckBox() automatic_tracking_checkbox:SetSize(24, 24) - f.AutomaticTrackingCheckbox = automatic_tracking_checkbox - + newAuraPanel.AutomaticTrackingCheckbox = automatic_tracking_checkbox + local automatic_tracking_label = DF:CreateLabel(background_method_selection, "Automatic") automatic_tracking_label:SetPoint("left", automatic_tracking_checkbox, "right", 2, 0) - - local manual_tracking_checkbox = DF:CreateSwitch(background_method_selection, on_switch_tracking_method, f.db.aura_tracker.track_method == 0x2, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, DF:GetTemplate("switch", "OPTIONS_CHECKBOX_BRIGHT_TEMPLATE")) + + local manual_tracking_checkbox = DF:CreateSwitch(background_method_selection, on_switch_tracking_method, newAuraPanel.db.aura_tracker.track_method == 0x2, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, DF:GetTemplate("switch", "OPTIONS_CHECKBOX_BRIGHT_TEMPLATE")) manual_tracking_checkbox.Method = 0x2 manual_tracking_checkbox:SetAsCheckBox() manual_tracking_checkbox:SetSize(24, 24) - f.ManualTrackingCheckbox = manual_tracking_checkbox - + newAuraPanel.ManualTrackingCheckbox = manual_tracking_checkbox + local manual_tracking_label = DF:CreateLabel(background_method_selection, "Manual") manual_tracking_label:SetPoint("left", manual_tracking_checkbox, "right", 2, 0) - + automatic_tracking_checkbox:SetPoint("topleft", tracking_method_label, "bottomleft", 0, -6) manual_tracking_checkbox:SetPoint("topleft", automatic_tracking_checkbox, "bottomleft", 0, -6) - + -------- anchors points local y = -110 -------- automatic - + --manual add the buff and ebuff names local AllSpellsMap = {} local AllSpellNames = {} - + --store a table with spell name as key and in the value an index table with spell IDs local AllSpellsSameName = {} - + local load_all_spells = function(self, capsule) - if (not next (AllSpellsMap)) then - DF:LoadAllSpells (AllSpellsMap, AllSpellNames, AllSpellsSameName) - - f_auto.AddBuffBlacklistTextBox.SpellAutoCompleteList = AllSpellNames - f_auto.AddDebuffBlacklistTextBox.SpellAutoCompleteList = AllSpellNames - f_auto.AddBuffTracklistTextBox.SpellAutoCompleteList = AllSpellNames - f_auto.AddDebuffTracklistTextBox.SpellAutoCompleteList = AllSpellNames - - f_manual.NewBuffTextBox.SpellAutoCompleteList = AllSpellNames - f_manual.NewDebuffTextBox.SpellAutoCompleteList = AllSpellNames - + if (not next(AllSpellsMap)) then + DF:LoadAllSpells(AllSpellsMap, AllSpellNames, AllSpellsSameName) + + auraPanel_Auto.AddBuffBlacklistTextBox.SpellAutoCompleteList = AllSpellNames + auraPanel_Auto.AddDebuffBlacklistTextBox.SpellAutoCompleteList = AllSpellNames + auraPanel_Auto.AddBuffTracklistTextBox.SpellAutoCompleteList = AllSpellNames + auraPanel_Auto.AddDebuffTracklistTextBox.SpellAutoCompleteList = AllSpellNames + + auraPanel_Manual.NewBuffTextBox.SpellAutoCompleteList = AllSpellNames + auraPanel_Manual.NewDebuffTextBox.SpellAutoCompleteList = AllSpellNames + -- - - f_auto.AddBuffBlacklistTextBox:SetAsAutoComplete ("SpellAutoCompleteList") - f_auto.AddDebuffBlacklistTextBox:SetAsAutoComplete ("SpellAutoCompleteList") - f_auto.AddBuffTracklistTextBox:SetAsAutoComplete ("SpellAutoCompleteList") - f_auto.AddDebuffTracklistTextBox:SetAsAutoComplete ("SpellAutoCompleteList") - - f_manual.NewBuffTextBox:SetAsAutoComplete ("SpellAutoCompleteList") - f_manual.NewDebuffTextBox:SetAsAutoComplete ("SpellAutoCompleteList") - + + auraPanel_Auto.AddBuffBlacklistTextBox:SetAsAutoComplete("SpellAutoCompleteList") + auraPanel_Auto.AddDebuffBlacklistTextBox:SetAsAutoComplete("SpellAutoCompleteList") + auraPanel_Auto.AddBuffTracklistTextBox:SetAsAutoComplete("SpellAutoCompleteList") + auraPanel_Auto.AddDebuffTracklistTextBox:SetAsAutoComplete("SpellAutoCompleteList") + + auraPanel_Manual.NewBuffTextBox:SetAsAutoComplete("SpellAutoCompleteList") + auraPanel_Manual.NewDebuffTextBox:SetAsAutoComplete("SpellAutoCompleteList") + -- - - f_auto.AddBuffBlacklistTextBox.ShouldOptimizeAutoComplete = true - f_auto.AddDebuffBlacklistTextBox.ShouldOptimizeAutoComplete = true - f_auto.AddBuffTracklistTextBox.ShouldOptimizeAutoComplete = true - f_auto.AddDebuffTracklistTextBox.ShouldOptimizeAutoComplete = true - - f_manual.NewBuffTextBox.ShouldOptimizeAutoComplete = true - f_manual.NewDebuffTextBox.ShouldOptimizeAutoComplete = true + + auraPanel_Auto.AddBuffBlacklistTextBox.ShouldOptimizeAutoComplete = true + auraPanel_Auto.AddDebuffBlacklistTextBox.ShouldOptimizeAutoComplete = true + auraPanel_Auto.AddBuffTracklistTextBox.ShouldOptimizeAutoComplete = true + auraPanel_Auto.AddDebuffTracklistTextBox.ShouldOptimizeAutoComplete = true + + auraPanel_Manual.NewBuffTextBox.ShouldOptimizeAutoComplete = true + auraPanel_Manual.NewDebuffTextBox.ShouldOptimizeAutoComplete = true end end - + --this set the width of the background box, text entry and button local textEntryWidth = 120 --create the background - local background_add_blacklist = CreateFrame("frame", nil, f_auto, "BackdropTemplate") + local background_add_blacklist = CreateFrame("frame", nil, auraPanel_Auto, "BackdropTemplate") background_add_blacklist:SetSize(textEntryWidth + 10, 135) DF:ApplyStandardBackdrop(background_add_blacklist) background_add_blacklist.__background:SetVertexColor(0.47, 0.27, 0.27) - - local background_add_tracklist = CreateFrame("frame", nil, f_auto, "BackdropTemplate") + + local background_add_tracklist = CreateFrame("frame", nil, auraPanel_Auto, "BackdropTemplate") background_add_tracklist:SetSize(textEntryWidth + 10, 135) DF:ApplyStandardBackdrop(background_add_tracklist) background_add_tracklist.__background:SetVertexColor(0.27, 0.27, 0.47) - + --black list --create labels local buff_blacklist_label = self:CreateLabel(background_add_blacklist, texts.MANUAL_ADD_BLACKLIST_BUFF, DF:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) local debuff_blacklist_label = self:CreateLabel(background_add_blacklist, texts.MANUAL_ADD_BLACKLIST_DEBUFF, DF:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) - + local buff_name_blacklist_entry = self:CreateTextEntry(background_add_blacklist, function()end, textEntryWidth, 20, "AddBuffBlacklistTextBox", _, _, options_dropdown_template) buff_name_blacklist_entry:SetHook("OnEditFocusGained", load_all_spells) buff_name_blacklist_entry:SetJustifyH("left") buff_name_blacklist_entry.tooltip = "Enter the buff name using lower case letters." - f_auto.AddBuffBlacklistTextBox = buff_name_blacklist_entry - + auraPanel_Auto.AddBuffBlacklistTextBox = buff_name_blacklist_entry + local debuff_name_blacklist_entry = self:CreateTextEntry(background_add_blacklist, function()end, textEntryWidth, 20, "AddDebuffBlacklistTextBox", _, _, options_dropdown_template) debuff_name_blacklist_entry:SetHook("OnEditFocusGained", load_all_spells) debuff_name_blacklist_entry:SetJustifyH("left") debuff_name_blacklist_entry.tooltip = "Enter the debuff name using lower case letters." - f_auto.AddDebuffBlacklistTextBox = debuff_name_blacklist_entry - + auraPanel_Auto.AddDebuffBlacklistTextBox = debuff_name_blacklist_entry + local same_name_spells_add = function(spellID, t) local spellName = GetSpellInfo(spellID) if (spellName) then - if (not next (AllSpellsMap)) then + if (not next(AllSpellsMap)) then load_all_spells() end - - spellName = lower (spellName) + + spellName = lower(spellName) local spellWithSameName = AllSpellsSameName [spellName] if (spellWithSameName) then if (t) then @@ -385,7 +382,7 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t end end DF.AddSpellWithSameName = same_name_spells_add - + local get_spellID_from_string = function(text) --check if the user entered a spell ID local isSpellID = tonumber(text) @@ -397,285 +394,285 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t return end end - + --get the spell ID from the spell name - text = lower (text) + text = lower(text) local spellID = AllSpellsMap [text] if (not spellID) then return end - + return spellID end - + local add_blacklist_buff_button = self:CreateButton(background_add_blacklist, function() local text = buff_name_blacklist_entry.text buff_name_blacklist_entry:SetText("") buff_name_blacklist_entry:ClearFocus() - + if (text ~= "") then --get the spellId - local spellId = get_spellID_from_string (text) + local spellId = get_spellID_from_string(text) if (not spellId) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Spell not found!") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") return end - - --add the spellName to the blacklist - f.db.aura_tracker.buff_banned [spellId] = true - - --refresh the buff blacklist frame - f.buff_ignored:DoRefresh() - DF:QuickDispatch(change_callback) - + --add the spellName to the blacklist + newAuraPanel.db.aura_tracker.buff_banned [spellId] = true + + --refresh the buff blacklist frame + newAuraPanel.buff_ignored:DoRefresh() + + DF:QuickDispatch(changeCallback) + --add to spells with the same name cache - same_name_spells_add (spellId) + same_name_spells_add(spellId) end - + end, textEntryWidth/2 -3, 20, "By Name", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate("font", options.button_text_template)) - + local add_blacklist_buff_button_id = self:CreateButton(background_add_blacklist, function() local text = buff_name_blacklist_entry.text buff_name_blacklist_entry:SetText("") buff_name_blacklist_entry:ClearFocus() - + if (text ~= "") then if (not tonumber(text)) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Invalid Spell-ID.") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID.") end - + --get the spellId - local spellId = get_spellID_from_string (text) + local spellId = get_spellID_from_string(text) if (not spellId) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Spell not found!") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") return end - - --add the spellId to the blacklist - f.db.aura_tracker.buff_banned [spellId] = false - - --refresh the buff blacklist frame - f.buff_ignored:DoRefresh() - DF:QuickDispatch(change_callback) - + --add the spellId to the blacklist + newAuraPanel.db.aura_tracker.buff_banned [spellId] = false + + --refresh the buff blacklist frame + newAuraPanel.buff_ignored:DoRefresh() + + DF:QuickDispatch(changeCallback) + --add to spells with the same name cache - same_name_spells_add (spellId) + same_name_spells_add(spellId) end - + end, textEntryWidth/2 -3, 20, "By ID", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate("font", options.button_text_template)) - + local add_blacklist_debuff_button = self:CreateButton(background_add_blacklist, function() local text = debuff_name_blacklist_entry.text debuff_name_blacklist_entry:SetText("") debuff_name_blacklist_entry:ClearFocus() - + if (text ~= "") then --get the spellId - local spellId = get_spellID_from_string (text) + local spellId = get_spellID_from_string(text) if (not spellId) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Spell not found!") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") return end - + --add the spellName to the blacklist - f.db.aura_tracker.debuff_banned [spellId] = true - + newAuraPanel.db.aura_tracker.debuff_banned [spellId] = true + --refresh the buff blacklist frame - f.debuff_ignored:DoRefresh() - - DF:QuickDispatch(change_callback) - + newAuraPanel.debuff_ignored:DoRefresh() + + DF:QuickDispatch(changeCallback) + --add to spells with the same name cache - same_name_spells_add (spellId) + same_name_spells_add(spellId) end end, textEntryWidth/2 -3, 20, "By Name", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate("font", options.button_text_template)) - + local add_blacklist_debuff_button_id = self:CreateButton(background_add_blacklist, function() local text = debuff_name_blacklist_entry.text debuff_name_blacklist_entry:SetText("") debuff_name_blacklist_entry:ClearFocus() - + if (text ~= "") then if (not tonumber(text)) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Invalid Spell-ID.") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID.") end - + --get the spellId - local spellId = get_spellID_from_string (text) + local spellId = get_spellID_from_string(text) if (not spellId) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Spell not found!") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") return end - + --add the spellId to the blacklist - f.db.aura_tracker.debuff_banned [spellId] = false - + newAuraPanel.db.aura_tracker.debuff_banned [spellId] = false + --refresh the buff blacklist frame - f.debuff_ignored:DoRefresh() - - DF:QuickDispatch(change_callback) - + newAuraPanel.debuff_ignored:DoRefresh() + + DF:QuickDispatch(changeCallback) + --add to spells with the same name cache - same_name_spells_add (spellId) + same_name_spells_add(spellId) end - end, textEntryWidth/2 -3, 20, "By ID", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate("font", options.button_text_template)) - - + end, textEntryWidth/2 -3, 20, "By ID", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate("font", options.button_text_template)) + + --track list local buff_tracklist_label = self:CreateLabel(background_add_tracklist, texts.MANUAL_ADD_TRACKLIST_BUFF, DF:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) local debuff_tracklist_label = self:CreateLabel(background_add_tracklist, texts.MANUAL_ADD_TRACKLIST_DEBUFF, DF:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) - + local buff_name_tracklist_entry = self:CreateTextEntry(background_add_tracklist, function()end, textEntryWidth, 20, "AddBuffTracklistTextBox", _, _, options_dropdown_template) buff_name_tracklist_entry:SetHook("OnEditFocusGained", load_all_spells) buff_name_tracklist_entry:SetJustifyH("left") buff_name_tracklist_entry.tooltip = "Enter the buff name using lower case letters." - f_auto.AddBuffTracklistTextBox = buff_name_tracklist_entry - + auraPanel_Auto.AddBuffTracklistTextBox = buff_name_tracklist_entry + local debuff_name_tracklist_entry = self:CreateTextEntry(background_add_tracklist, function()end, textEntryWidth, 20, "AddDebuffTracklistTextBox", _, _, options_dropdown_template) debuff_name_tracklist_entry:SetHook("OnEditFocusGained", load_all_spells) debuff_name_tracklist_entry:SetJustifyH("left") debuff_name_tracklist_entry.tooltip = "Enter the debuff name using lower case letters." - f_auto.AddDebuffTracklistTextBox = debuff_name_tracklist_entry - + auraPanel_Auto.AddDebuffTracklistTextBox = debuff_name_tracklist_entry + local add_tracklist_debuff_button = self:CreateButton(background_add_tracklist, function() local text = debuff_name_tracklist_entry.text debuff_name_tracklist_entry:SetText("") debuff_name_tracklist_entry:ClearFocus() - + if (text ~= "") then --get the spellId - local spellId = get_spellID_from_string (text) + local spellId = get_spellID_from_string(text) if (not spellId) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Spell not found!") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") return end - + --add the spellName to the tracklist - f.db.aura_tracker.debuff_tracked [spellId] = true - + newAuraPanel.db.aura_tracker.debuff_tracked [spellId] = true + --refresh the buff blacklist frame - f.debuff_tracked:DoRefresh() - - DF:QuickDispatch(change_callback) - + newAuraPanel.debuff_tracked:DoRefresh() + + DF:QuickDispatch(changeCallback) + --add to spells with the same name cache - same_name_spells_add (spellId) + same_name_spells_add(spellId) end end, textEntryWidth/2 -3, 20, "By Name", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate("font", options.button_text_template)) - + local add_tracklist_debuff_button_id = self:CreateButton(background_add_tracklist, function() local text = debuff_name_tracklist_entry.text debuff_name_tracklist_entry:SetText("") debuff_name_tracklist_entry:ClearFocus() - + if (text ~= "") then if (not tonumber(text)) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Invalid Spell-ID.") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID.") end - + --get the spellId - local spellId = get_spellID_from_string (text) + local spellId = get_spellID_from_string(text) if (not spellId) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Spell not found!") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") return end - - f.db.aura_tracker.debuff_tracked [spellId] = false - + + newAuraPanel.db.aura_tracker.debuff_tracked [spellId] = false + --refresh the buff blacklist frame - f.debuff_tracked:DoRefresh() - - DF:QuickDispatch(change_callback) - + newAuraPanel.debuff_tracked:DoRefresh() + + DF:QuickDispatch(changeCallback) + --add to spells with the same name cache - same_name_spells_add (spellId) + same_name_spells_add(spellId) end end, textEntryWidth/2 -3, 20, "By ID", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate("font", options.button_text_template)) - + local add_tracklist_buff_button = self:CreateButton(background_add_tracklist, function() local text = buff_name_tracklist_entry.text buff_name_tracklist_entry:SetText("") buff_name_tracklist_entry:ClearFocus() - + if (text ~= "") then --get the spellId - local spellId = get_spellID_from_string (text) + local spellId = get_spellID_from_string(text) if (not spellId) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Spell not found!") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") return end - + --add the spellName to the tracklist - f.db.aura_tracker.buff_tracked [spellId] = true - + newAuraPanel.db.aura_tracker.buff_tracked [spellId] = true + --refresh the buff tracklist frame - f.buff_tracked:DoRefresh() + newAuraPanel.buff_tracked:DoRefresh() --callback the addon - DF:QuickDispatch(change_callback) - + DF:QuickDispatch(changeCallback) + --add to spells with the same name cache - same_name_spells_add (spellId) + same_name_spells_add(spellId) end - + end, textEntryWidth/2 -3, 20, "By Name", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate("font", options.button_text_template)) - + local add_tracklist_buff_button_id = self:CreateButton(background_add_tracklist, function() local text = buff_name_tracklist_entry.text buff_name_tracklist_entry:SetText("") buff_name_tracklist_entry:ClearFocus() - + if (text ~= "") then if (not tonumber(text)) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Invalid Spell-ID.") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Invalid Spell-ID.") end - + --get the spellId - local spellId = get_spellID_from_string (text) + local spellId = get_spellID_from_string(text) if (not spellId) then - DetailsFramework.Msg ({__name = "DetailsFramework"}, "Spell not found!") + DetailsFramework.Msg({__name = "DetailsFramework"}, "Spell not found!") return end - + --add the spellId to the tracklist - f.db.aura_tracker.buff_tracked [spellId] = false - + newAuraPanel.db.aura_tracker.buff_tracked [spellId] = false + --refresh the buff tracklist frame - f.buff_tracked:DoRefresh() + newAuraPanel.buff_tracked:DoRefresh() --callback the addon - DF:QuickDispatch(change_callback) - + DF:QuickDispatch(changeCallback) + --add to spells with the same name cache - same_name_spells_add (spellId) + same_name_spells_add(spellId) end end, textEntryWidth/2 -3, 20, "By ID", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"), DF:GetTemplate("font", options.button_text_template)) - + --anchors: - background_add_blacklist:SetPoint("topleft", f_auto, "topleft", 0, y) + background_add_blacklist:SetPoint("topleft", auraPanel_Auto, "topleft", 0, y) background_add_tracklist:SetPoint("topleft", background_add_blacklist, "bottomleft", 0, -10) - + --debuff blacklist debuff_name_blacklist_entry:SetPoint("topleft", background_add_blacklist, "topleft", 5, -20) debuff_blacklist_label:SetPoint("bottomleft", debuff_name_blacklist_entry, "topleft", 0, 2) add_blacklist_debuff_button:SetPoint("topleft", debuff_name_blacklist_entry, "bottomleft", 0, -2) add_blacklist_debuff_button_id:SetPoint("left", add_blacklist_debuff_button, "right", 1, 0) - + --buff blacklist buff_blacklist_label:SetPoint("topleft", add_blacklist_debuff_button.widget, "bottomleft", 0, -10) buff_name_blacklist_entry:SetPoint("topleft", buff_blacklist_label, "bottomleft", 0, -2) add_blacklist_buff_button:SetPoint("topleft", buff_name_blacklist_entry, "bottomleft", 0, -2) add_blacklist_buff_button_id:SetPoint("left", add_blacklist_buff_button, "right", 1, 0) - + --debuff tracklist debuff_name_tracklist_entry:SetPoint("topleft", background_add_tracklist, "topleft", 5, -20) debuff_tracklist_label:SetPoint("bottomleft", debuff_name_tracklist_entry, "topleft", 0, 2) add_tracklist_debuff_button:SetPoint("topleft", debuff_name_tracklist_entry, "bottomleft", 0, -2) add_tracklist_debuff_button_id:SetPoint("left", add_tracklist_debuff_button, "right", 1, 0) - + --buff tracklist buff_tracklist_label:SetPoint("topleft", add_tracklist_debuff_button.widget, "bottomleft", 0, -10) buff_name_tracklist_entry:SetPoint("topleft", buff_tracklist_label, "bottomleft", 0, -2) @@ -684,162 +681,176 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t local ALL_BUFFS = {} local ALL_DEBUFFS = {} - + --options passed to the create aura panel local width, height, row_height = options.width, options.height, options.row_height - local autoTrackList_LineOnEnter = function(self, capsule, value) - + local autoTrackList_LineOnEnter = function(self, capsule, value) + local flag = self.Flag value = value or self.SpellID - + if not flag then GameCooltip2:Preset(2) GameCooltip2:SetOwner(self, "left", "right", 2, 0) GameCooltip2:SetOption("TextSize", 10) - + local spellName, _, spellIcon = GetSpellInfo(value) if (spellName) then - GameCooltip2:AddLine(spellName .. " (" .. value .. ")") - GameCooltip2:AddIcon (spellIcon, 1, 1, 14, 14, .1, .9, .1, .9) + GameCooltip2:AddLine(spellName .. "(" .. value .. ")") + GameCooltip2:AddIcon(spellIcon, 1, 1, 14, 14, .1, .9, .1, .9) end GameCooltip2:Show() else - - local spellName = GetSpellInfo(value) - if (spellName) then - local spellsWithSameName = db.aura_cache_by_name [lower (spellName)] + local spellName = GetSpellInfo(value) + if (spellName) then + + local spellsWithSameName = db.aura_cache_by_name [lower(spellName)] if (not spellsWithSameName) then - same_name_spells_add (value) - spellsWithSameName = db.aura_cache_by_name [lower (spellName)] + same_name_spells_add(value) + spellsWithSameName = db.aura_cache_by_name [lower(spellName)] end - + if (spellsWithSameName) then GameCooltip2:Preset(2) GameCooltip2:SetOwner(self, "left", "right", 2, 0) GameCooltip2:SetOption("TextSize", 10) - + for i, spellID in ipairs(spellsWithSameName) do local spellName, _, spellIcon = GetSpellInfo(spellID) if (spellName) then - GameCooltip2:AddLine(spellName .. " (" .. spellID .. ")") - GameCooltip2:AddIcon (spellIcon, 1, 1, 14, 14, .1, .9, .1, .9) + GameCooltip2:AddLine(spellName .. "(" .. spellID .. ")") + GameCooltip2:AddIcon(spellIcon, 1, 1, 14, 14, .1, .9, .1, .9) end end - + GameCooltip2:Show() end end - + end end - + local autoTrackList_LineOnLeave = function() GameCooltip2:Hide() end - + local scrollWidth = 208 local scrollHeight = 343 local lineAmount = 18 local lineHeight = 18 local backdropColor = {.8, .8, .8, 0.2} local backdropColor_OnEnter = {.8, .8, .8, 0.4} - - local createAuraScrollBox = function(parent, name, member, title, db, removeFunc) - + + --aura scroll box default settings + local auraScrollDefaultSettings = { + show_spell_tooltip = false, + line_height = 18, + line_amount = 18, + } + + local createAuraScrollBox = function(scrollBoxParent, scrollBoxName, scrollBoxParentKey, scrollBoxTitle, databaseTable, removeAuraFunc, options) + local scrollOptions = {} + detailsFramework.OptionsFunctions.BuildOptionsTable(scrollOptions, auraScrollDefaultSettings, options) + local updateFunc = function(self, data, offset, totalLines) for i = 1, totalLines do local index = i + offset - local auraTable = data [index] + local auraTable = data[index] if (auraTable) then - local line = self:GetLine (i) - local spellID, spellName, spellIcon, lowerSpellName, flag = unpack(auraTable) - - line.SpellID = spellID + local line = self:GetLine(i) + local spellId, spellName, spellIcon, lowerSpellName, flag = unpack(auraTable) + + line.SpellID = spellId line.SpellName = spellName line.SpellNameLower = lowerSpellName line.SpellIcon = spellIcon line.Flag = flag - - if flag then + + if (flag) then line.name:SetText(spellName) else - line.name:SetText(spellName .. " (" .. spellID .. ")") + line.name:SetText(spellName .. "(" .. spellId .. ")") end + line.icon:SetTexture(spellIcon) line.icon:SetTexCoord(.1, .9, .1, .9) end end end - - local lineOnEnter = function(self) - self:SetBackdropColor(unpack(backdropColor_OnEnter)) - --GameTooltip:SetOwner(self, "ANCHOR_CURSOR") - --GameTooltip:SetSpellByID(self.SpellID) - --GameTooltip:AddLine(" ") - --GameTooltip:Show() + local auraLineOnEnter = function(line) + if (scrollOptions.options.show_spell_tooltip and line.SpellID and GetSpellInfo(line.SpellID)) then + GameTooltip:SetOwner(line, "ANCHOR_CURSOR") + GameTooltip:SetSpellByID(line.SpellID) + GameTooltip:AddLine(" ") + GameTooltip:Show() + end + + line:SetBackdropColor(unpack(backdropColor_OnEnter)) end - - local lineOnLeave = function(self) + + local auraLineOnLeave = function(self) self:SetBackdropColor(unpack(backdropColor)) - --GameTooltip:Hide() + GameTooltip:Hide() end - - local onRemoveClick = function(self) - local spellID = self:GetParent().SpellID - db [spellID] = nil - db ["".. (spellID or "")] = nil -- cleanup... - parent [member]:DoRefresh() - if (removeFunc) then - DF:QuickDispatch(removeFunc) + + local onAuraRemoveButtonClick = function(self) + local spellId = self:GetParent().SpellID + databaseTable[spellId] = nil + databaseTable["" .. (spellId or "")] = nil -- cleanup... + scrollBoxParent[scrollBoxParentKey]:DoRefresh() + if (removeAuraFunc) then --upvalue + detailsFramework:QuickDispatch(removeAuraFunc) end end - + local createLineFunc = function(self, index) local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate") - line:SetPoint("topleft", self, "topleft", 1, - ((index - 1) * (lineHeight + 1)) - 1) + local lineHeight = scrollOptions.options.line_height + + line:SetPoint("topleft", self, "topleft", 1, -((index - 1) * (lineHeight + 1)) - 1) line:SetSize(scrollWidth - 2, lineHeight) line:SetScript("OnEnter", autoTrackList_LineOnEnter) - line:HookScript ("OnEnter", lineOnEnter) + line:HookScript("OnEnter", auraLineOnEnter) line:SetScript("OnLeave", autoTrackList_LineOnLeave) - line:HookScript ("OnLeave", lineOnLeave) - + line:HookScript("OnLeave", auraLineOnLeave) + line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) line:SetBackdropColor(unpack(backdropColor)) - + local icon = line:CreateTexture("$parentIcon", "overlay") icon:SetSize(lineHeight - 2, lineHeight - 2) - + local name = line:CreateFontString("$parentName", "overlay", "GameFontNormal") DF:SetFontSize(name, 10) - local remove_button = CreateFrame("button", "$parentRemoveButton", line, "UIPanelCloseButton") - remove_button:SetSize(16, 16) - remove_button:SetScript("OnClick", onRemoveClick) - remove_button:SetPoint("topright", line, "topright") - remove_button:GetNormalTexture():SetDesaturated(true) - + local removeButton = CreateFrame("button", "$parentRemoveButton", line, "UIPanelCloseButton") + removeButton:SetSize(16, 16) + removeButton:SetScript("OnClick", onAuraRemoveButtonClick) + removeButton:SetPoint("topright", line, "topright") + removeButton:GetNormalTexture():SetDesaturated(true) + icon:SetPoint("left", line, "left", 2, 0) name:SetPoint("left", icon, "right", 3, 0) - + line.icon = icon line.name = name - line.removebutton = remove_button - + line.removebutton = removeButton + return line end - local scroll = DF:CreateScrollBox (parent, name, updateFunc, db, scrollWidth, scrollHeight, lineAmount, lineHeight) - DF:ReskinSlider(scroll) - parent [member] = scroll - scroll.OriginalData = db - - function scroll:DoRefresh() + local auraScrollBox = DF:CreateScrollBox(scrollBoxParent, scrollBoxName, updateFunc, databaseTable, scrollWidth, scrollHeight, scrollOptions.options.line_amount, scrollOptions.options.line_height) + DF:ReskinSlider(auraScrollBox) + scrollBoxParent[scrollBoxParentKey] = auraScrollBox + auraScrollBox.OriginalData = databaseTable + + function auraScrollBox:DoRefresh() local t = {} local added = {} - for spellID, flag in pairs(scroll.OriginalData) do + for spellID, flag in pairs(auraScrollBox.OriginalData) do local spellName, _, spellIcon = GetSpellInfo(spellID) if (spellName and not added[tonumber(spellID) or 0]) then local lowerSpellName = spellName:lower() @@ -847,109 +858,109 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t added[tonumber(spellID) or 0] = true end end - - table.sort (t, function(t1, t2) return t1[4] < t2[4] end) - - self:SetData (t) + + table.sort(t, function(t1, t2) return t1[4] < t2[4] end) + + self:SetData(t) self:Refresh() end - - function scroll:DoSetData (newDB) - self:SetData (newDB) - scroll.OriginalData = newDB + + function auraScrollBox:DoSetData(newDB) + self:SetData(newDB) + auraScrollBox.OriginalData = newDB self:DoRefresh() end - - local title = DF:CreateLabel(parent, title) - title.textcolor = "silver" - title.textsize = 10 - title:SetPoint("bottomleft", scroll, "topleft", 0, 2) + + local titleLabel = DF:CreateLabel(scrollBoxParent, scrollBoxTitle) + titleLabel.textcolor = "silver" + titleLabel.textsize = 10 + titleLabel:SetPoint("bottomleft", auraScrollBox, "topleft", 0, 2) for i = 1, lineAmount do - scroll:CreateLine (createLineFunc) + auraScrollBox:CreateLine(createLineFunc) end - - scroll:DoRefresh() - return scroll + + auraScrollBox:DoRefresh() + return auraScrollBox end - - local buff_tracked = createAuraScrollBox (f_auto, "$parentBuffTracked", "BuffTrackerScroll", f.LocTexts.BUFFS_TRACKED, f.db.aura_tracker.buff_tracked, function() - if (change_callback) then - DF:QuickDispatch(change_callback) + + local buff_tracked = createAuraScrollBox(auraPanel_Auto, "$parentBuffTracked", "BuffTrackerScroll", newAuraPanel.LocTexts.BUFFS_TRACKED, newAuraPanel.db.aura_tracker.buff_tracked, function() + if (changeCallback) then + DF:QuickDispatch(changeCallback) end end) - local debuff_tracked = createAuraScrollBox (f_auto, "$parentDebuffTracked", "DebuffTrackerScroll", f.LocTexts.DEBUFFS_TRACKED, f.db.aura_tracker.debuff_tracked, function() - if (change_callback) then - DF:QuickDispatch(change_callback) + local debuff_tracked = createAuraScrollBox(auraPanel_Auto, "$parentDebuffTracked", "DebuffTrackerScroll", newAuraPanel.LocTexts.DEBUFFS_TRACKED, newAuraPanel.db.aura_tracker.debuff_tracked, function() + if (changeCallback) then + DF:QuickDispatch(changeCallback) end end) - - local buff_ignored = createAuraScrollBox (f_auto, "$parentBuffIgnored", "BuffIgnoredScroll", f.LocTexts.BUFFS_IGNORED, f.db.aura_tracker.buff_banned, function() - if (change_callback) then - DF:QuickDispatch(change_callback) + + local buff_ignored = createAuraScrollBox(auraPanel_Auto, "$parentBuffIgnored", "BuffIgnoredScroll", newAuraPanel.LocTexts.BUFFS_IGNORED, newAuraPanel.db.aura_tracker.buff_banned, function() + if (changeCallback) then + DF:QuickDispatch(changeCallback) end end) - local debuff_ignored = createAuraScrollBox (f_auto, "$parentDebuffIgnored", "DebuffIgnoredScroll", f.LocTexts.DEBUFFS_IGNORED, f.db.aura_tracker.debuff_banned, function() - if (change_callback) then - DF:QuickDispatch(change_callback) + local debuff_ignored = createAuraScrollBox(auraPanel_Auto, "$parentDebuffIgnored", "DebuffIgnoredScroll", newAuraPanel.LocTexts.DEBUFFS_IGNORED, newAuraPanel.db.aura_tracker.debuff_banned, function() + if (changeCallback) then + DF:QuickDispatch(changeCallback) end end) - + local xLocation = 140 scrollWidth = scrollWidth + 20 - - debuff_ignored:SetPoint("topleft", f_auto, "topleft", 0 + xLocation, y) - buff_ignored:SetPoint("topleft", f_auto, "topleft", 8 + scrollWidth + xLocation, y) - debuff_tracked:SetPoint("topleft", f_auto, "topleft", 16 + (scrollWidth * 2) + xLocation, y) - buff_tracked:SetPoint("topleft", f_auto, "topleft", 24 + (scrollWidth * 3) + xLocation, y) - f.buff_ignored = buff_ignored - f.debuff_ignored = debuff_ignored - f.buff_tracked = buff_tracked - f.debuff_tracked = debuff_tracked + debuff_ignored:SetPoint("topleft", auraPanel_Auto, "topleft", 0 + xLocation, y) + buff_ignored:SetPoint("topleft", auraPanel_Auto, "topleft", 8 + scrollWidth + xLocation, y) + debuff_tracked:SetPoint("topleft", auraPanel_Auto, "topleft", 16 +(scrollWidth * 2) + xLocation, y) + buff_tracked:SetPoint("topleft", auraPanel_Auto, "topleft", 24 +(scrollWidth * 3) + xLocation, y) - f_auto:SetScript("OnShow", function() + newAuraPanel.buff_ignored = buff_ignored + newAuraPanel.debuff_ignored = debuff_ignored + newAuraPanel.buff_tracked = buff_tracked + newAuraPanel.debuff_tracked = debuff_tracked + + auraPanel_Auto:SetScript("OnShow", function() for i = 1, BUFF_MAX_DISPLAY do - local name, texture, count, debuffType, duration, expirationTime, caster, _, nameplateShowPersonal, spellId, _, _, _, nameplateShowAll = UnitAura ("player", i, "HELPFUL") + local name, texture, count, debuffType, duration, expirationTime, caster, _, nameplateShowPersonal, spellId, _, _, _, nameplateShowAll = UnitAura("player", i, "HELPFUL") if (name) then ALL_BUFFS [spellId] = true end - local name, texture, count, debuffType, duration, expirationTime, caster, _, nameplateShowPersonal, spellId, _, _, _, nameplateShowAll = UnitAura ("player", i, "HARMFUL") + local name, texture, count, debuffType, duration, expirationTime, caster, _, nameplateShowPersonal, spellId, _, _, _, nameplateShowAll = UnitAura("player", i, "HARMFUL") if (name) then ALL_DEBUFFS [spellId] = true end end - + buff_tracked:DoRefresh() debuff_tracked:DoRefresh() buff_ignored:DoRefresh() debuff_ignored:DoRefresh() - + end) - f_auto:SetScript("OnHide", function() + auraPanel_Auto:SetScript("OnHide", function() -- end) --show the frame selecton on the f.db - if (f.db.aura_tracker.track_method == 0x1) then - on_switch_tracking_method (automatic_tracking_checkbox) - elseif (f.db.aura_tracker.track_method == 0x2) then - on_switch_tracking_method (manual_tracking_checkbox) + if (newAuraPanel.db.aura_tracker.track_method == 0x1) then + on_switch_tracking_method(automatic_tracking_checkbox) + elseif (newAuraPanel.db.aura_tracker.track_method == 0x2) then + on_switch_tracking_method(manual_tracking_checkbox) end - + -------manual --build the two aura scrolls for buff and debuff - + local scroll_width = width local scroll_height = height local scroll_lines = 15 local scroll_line_height = 20 - + local backdrop_color = {.8, .8, .8, 0.2} local backdrop_color_on_enter = {.8, .8, .8, 0.4} - + local line_onenter = function(self) self:SetBackdropColor(unpack(backdrop_color_on_enter)) local spellid = select(7, GetSpellInfo(self.value)) @@ -960,39 +971,39 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t GameTooltip:Show() end end - + local line_onleave = function(self) self:SetBackdropColor(unpack(backdrop_color)) GameTooltip:Hide() end - + local onclick_remove_button = function(self) local spell = self:GetParent().value local data = self:GetParent():GetParent():GetData() - + for i = 1, #data do if (data[i] == spell) then tremove(data, i) break end end - + self:GetParent():GetParent():Refresh() end - + local scroll_createline = function(self, index) local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate") line:SetPoint("topleft", self, "topleft", 1, -((index-1)*(scroll_line_height+1)) - 1) line:SetSize(scroll_width - 2, scroll_line_height) line:SetScript("OnEnter", line_onenter) line:SetScript("OnLeave", line_onleave) - + line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) line:SetBackdropColor(unpack(backdrop_color)) - + local icon = line:CreateTexture("$parentIcon", "overlay") icon:SetSize(scroll_line_height - 2, scroll_line_height - 2) - + local name = line:CreateFontString("$parentName", "overlay", "GameFontNormal") local remove_button = CreateFrame("button", "$parentRemoveButton", line, "UIPanelCloseButton") @@ -1000,14 +1011,14 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t remove_button:SetScript("OnClick", onclick_remove_button) remove_button:SetPoint("topright", line, "topright") remove_button:GetNormalTexture():SetDesaturated(true) - + icon:SetPoint("left", line, "left", 2, 0) name:SetPoint("left", icon, "right", 2, 0) - + line.icon = icon line.name = name line.removebutton = remove_button - + return line end @@ -1016,7 +1027,7 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t local index = i + offset local aura = data [index] if (aura) then - local line = self:GetLine (i) + local line = self:GetLine(i) local name, _, icon = GetSpellInfo(aura) line.value = aura if (name) then @@ -1030,65 +1041,65 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t end end end - - local buffs_added = self:CreateScrollBox (f_manual, "$parentBuffsAdded", scroll_refresh, f.db.aura_tracker.buff, scroll_width, scroll_height, scroll_lines, scroll_line_height) - buffs_added:SetPoint("topleft", f_manual, "topleft", 0, y) + + local buffs_added = self:CreateScrollBox(auraPanel_Manual, "$parentBuffsAdded", scroll_refresh, newAuraPanel.db.aura_tracker.buff, scroll_width, scroll_height, scroll_lines, scroll_line_height) + buffs_added:SetPoint("topleft", auraPanel_Manual, "topleft", 0, y) DF:ReskinSlider(buffs_added) - - for i = 1, scroll_lines do - buffs_added:CreateLine (scroll_createline) + + for i = 1, scroll_lines do + buffs_added:CreateLine(scroll_createline) end - - local debuffs_added = self:CreateScrollBox (f_manual, "$parentDebuffsAdded", scroll_refresh, f.db.aura_tracker.debuff, scroll_width, scroll_height, scroll_lines, scroll_line_height) - debuffs_added:SetPoint("topleft", f_manual, "topleft", width+30, y) + + local debuffs_added = self:CreateScrollBox(auraPanel_Manual, "$parentDebuffsAdded", scroll_refresh, newAuraPanel.db.aura_tracker.debuff, scroll_width, scroll_height, scroll_lines, scroll_line_height) + debuffs_added:SetPoint("topleft", auraPanel_Manual, "topleft", width+30, y) DF:ReskinSlider(debuffs_added) - - for i = 1, scroll_lines do - debuffs_added:CreateLine (scroll_createline) + + for i = 1, scroll_lines do + debuffs_added:CreateLine(scroll_createline) end - - f.buffs_added = buffs_added - f.debuffs_added = debuffs_added - + + newAuraPanel.buffs_added = buffs_added + newAuraPanel.debuffs_added = debuffs_added + local buffs_added_name = DF:CreateLabel(buffs_added, "Buffs", 12, "silver") buffs_added_name:SetTemplate(DF:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) buffs_added_name:SetPoint("bottomleft", buffs_added, "topleft", 0, 2) buffs_added.Title = buffs_added_name - + local debuffs_added_name = DF:CreateLabel(debuffs_added, "Debuffs", 12, "silver") debuffs_added_name:SetTemplate(DF:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) debuffs_added_name:SetPoint("bottomleft", debuffs_added, "topleft", 0, 2) debuffs_added.Title = debuffs_added_name - + -- build the text entry to type the spellname - local new_buff_string = self:CreateLabel(f_manual, "Add Buff") - local new_debuff_string = self:CreateLabel(f_manual, "Add Debuff") - local new_buff_entry = self:CreateTextEntry(f_manual, function()end, 200, 20, "NewBuffTextBox", _, _, options_dropdown_template) - local new_debuff_entry = self:CreateTextEntry(f_manual, function()end, 200, 20, "NewDebuffTextBox", _, _, options_dropdown_template) - + local new_buff_string = self:CreateLabel(auraPanel_Manual, "Add Buff") + local new_debuff_string = self:CreateLabel(auraPanel_Manual, "Add Debuff") + local new_buff_entry = self:CreateTextEntry(auraPanel_Manual, function()end, 200, 20, "NewBuffTextBox", _, _, options_dropdown_template) + local new_debuff_entry = self:CreateTextEntry(auraPanel_Manual, function()end, 200, 20, "NewDebuffTextBox", _, _, options_dropdown_template) + new_buff_entry:SetHook("OnEditFocusGained", load_all_spells) new_debuff_entry:SetHook("OnEditFocusGained", load_all_spells) new_buff_entry.tooltip = "Enter the buff name using lower case letters.\n\nYou can add several spells at once using |cFFFFFF00;|r to separate each spell name." new_debuff_entry.tooltip = "Enter the debuff name using lower case letters.\n\nYou can add several spells at once using |cFFFFFF00;|r to separate each spell name." - + new_buff_entry:SetJustifyH("left") new_debuff_entry:SetJustifyH("left") - - local add_buff_button = self:CreateButton(f_manual, function() - + + local add_buff_button = self:CreateButton(auraPanel_Manual, function() + local text = new_buff_entry.text new_buff_entry:SetText("") new_buff_entry:ClearFocus() - + if (text ~= "") then --check for more than one spellname if (text:find(";")) then for _, spellName in ipairs({strsplit(";", text)}) do - spellName = self:trim (spellName) - local spellID = get_spellID_from_string (spellName) + spellName = self:trim(spellName) + local spellID = get_spellID_from_string(spellName) if (spellID) then - tinsert(f.db.aura_tracker.buff, spellID) + tinsert(newAuraPanel.db.aura_tracker.buff, spellID) --[[ if not tonumber(spellName) then tinsert(f.db.aura_tracker.buff, spellName) @@ -1102,13 +1113,13 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t end else --get the spellId - local spellID = get_spellID_from_string (text) + local spellID = get_spellID_from_string(text) if (not spellID) then print("spellIs for spell ", text, "not found") return end - - tinsert(f.db.aura_tracker.buff, spellID) + + tinsert(newAuraPanel.db.aura_tracker.buff, spellID) --[[ if not tonumber(text) then tinsert(f.db.aura_tracker.buff, text) @@ -1117,13 +1128,13 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t end ]]-- end - + buffs_added:Refresh() end - + end, 100, 20, "Add Buff", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")) - - local add_debuff_button = self:CreateButton(f_manual, function() + + local add_debuff_button = self:CreateButton(auraPanel_Manual, function() local text = new_debuff_entry.text new_debuff_entry:SetText("") new_debuff_entry:ClearFocus() @@ -1131,11 +1142,11 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t --check for more than one spellname if (text:find(";")) then for _, spellName in ipairs({strsplit(";", text)}) do - spellName = self:trim (spellName) - local spellID = get_spellID_from_string (spellName) - + spellName = self:trim(spellName) + local spellID = get_spellID_from_string(spellName) + if (spellID) then - tinsert(f.db.aura_tracker.debuff, spellID) + tinsert(newAuraPanel.db.aura_tracker.debuff, spellID) --[[ if not tonumber(spellName) then tinsert(f.db.aura_tracker.debuff, spellName) @@ -1149,13 +1160,13 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t end else --get the spellId - local spellID = get_spellID_from_string (text) + local spellID = get_spellID_from_string(text) if (not spellID) then print("spellIs for spell ", text, "not found") return end - - tinsert(f.db.aura_tracker.debuff, spellID) + + tinsert(newAuraPanel.db.aura_tracker.debuff, spellID) --[[ if not tonumber(text) then print(text) @@ -1166,20 +1177,20 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t end ]]-- end - + debuffs_added:Refresh() end end, 100, 20, "Add Debuff", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")) - + local multiple_spells_label = DF:CreateLabel(buffs_added, "You can add multiple auras at once by separating them with ';'.\nExample: Fireball; Frostbolt; Flamestrike", 10, "gray") multiple_spells_label:SetSize(350, 24) - multiple_spells_label:SetJustifyV ("top") - - local export_box = self:CreateTextEntry(f_manual, function()end, 242, 20, "ExportAuraTextBox", _, _, options_dropdown_template) - - local export_buff_button = self:CreateButton(f_manual, function() + multiple_spells_label:SetJustifyV("top") + + local export_box = self:CreateTextEntry(auraPanel_Manual, function()end, 242, 20, "ExportAuraTextBox", _, _, options_dropdown_template) + + local export_buff_button = self:CreateButton(auraPanel_Manual, function() local str = "" - for _, spellId in ipairs(f.db.aura_tracker.buff) do + for _, spellId in ipairs(newAuraPanel.db.aura_tracker.buff) do local spellName = GetSpellInfo(spellId) if (spellName) then str = str .. spellName .. "; " @@ -1188,95 +1199,76 @@ function DF:CreateAuraConfigPanel (parent, name, db, change_callback, options, t export_box.text = str export_box:SetFocus(true) export_box:HighlightText() - + end, 120, 20, "Export Buffs", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")) - - local export_debuff_button = self:CreateButton(f_manual, function() + + local export_debuff_button = self:CreateButton(auraPanel_Manual, function() local str = "" - for _, spellId in ipairs(f.db.aura_tracker.debuff) do + for _, spellId in ipairs(newAuraPanel.db.aura_tracker.debuff) do local spellName = GetSpellInfo(spellId) if (spellName) then str = str .. spellName .. "; " end end - + export_box.text = str export_box:SetFocus(true) export_box:HighlightText() - + end, 120, 20, "Export Debuffs", nil, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")) - - new_buff_entry:SetPoint("topleft", f_manual, "topleft", 480, y) + + new_buff_entry:SetPoint("topleft", auraPanel_Manual, "topleft", 480, y) new_buff_string:SetPoint("bottomleft", new_buff_entry, "topleft", 0, 2) add_buff_button:SetPoint("left", new_buff_entry, "right", 2, 0) add_buff_button.tooltip = "Add the aura to be tracked.\n\nClick an aura on the list to remove it." - + new_debuff_string:SetPoint("topleft", new_buff_entry, "bottomleft", 0, -6) new_debuff_entry:SetPoint("topleft", new_debuff_string, "bottomleft", 0, -2) add_debuff_button:SetPoint("left", new_debuff_entry, "right", 2, 0) add_debuff_button.tooltip = "Add the aura to be tracked.\n\nClick an aura on the list to remove it." multiple_spells_label:SetPoint("topleft", new_debuff_entry, "bottomleft", 0, -6) - + export_buff_button:SetPoint("topleft", multiple_spells_label, "bottomleft", 0, -12) export_debuff_button:SetPoint("left",export_buff_button, "right", 2, 0) export_box:SetPoint("topleft", export_buff_button, "bottomleft", 0, -6) - + buffs_added:Refresh() debuffs_added:Refresh() - - ------------------------ ---------------------------------------------- ---------------------------------------------- ----------------------- - - f:SetScript("OnShow", function() + + newAuraPanel:SetScript("OnShow", function() buffs_added:Refresh() debuffs_added:Refresh() end) - - return f + + return newAuraPanel end -function DF:GetAllPlayerSpells (include_lower_case) +function DF:GetAllPlayerSpells(include_lower_case) local playerSpells = {} - local tab, tabTex, offset, numSpells = GetSpellTabInfo (2) + local tab, tabTex, offset, numSpells = GetSpellTabInfo(2) for i = 1, numSpells do local index = offset + i - local spellType, spellId = GetSpellBookItemInfo (index, "player") + local spellType, spellId = GetSpellBookItemInfo(index, "player") if (spellType == "SPELL") then local spellName = GetSpellInfo(spellId) tinsert(playerSpells, spellName) if (include_lower_case) then - tinsert(playerSpells, lower (spellName)) + tinsert(playerSpells, lower(spellName)) end end end return playerSpells end -function DF:SetAutoCompleteWithSpells (textentry) +function DF:SetAutoCompleteWithSpells(textentry) textentry:SetHook("OnEditFocusGained", function() - local playerSpells = DF:GetAllPlayerSpells (true) + local playerSpells = DF:GetAllPlayerSpells(true) textentry.WordList = playerSpells end) - textentry:SetAsAutoComplete ("WordList") + textentry:SetAsAutoComplete("WordList") end ---check for aura - - --- add aura - - ---handle savedvariables - - ---remove a aura - - - - - ---handle UNIT_AURA event diff --git a/Libs/DF/button.lua b/Libs/DF/button.lua index 2fed4404..da1150aa 100644 --- a/Libs/DF/button.lua +++ b/Libs/DF/button.lua @@ -382,6 +382,7 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) end ---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 ---@param width number|nil ---@param height number|nil @@ -464,6 +465,9 @@ detailsFramework:Mixin(ButtonMetaFunctions, detailsFramework.ScriptHookMixin) textSize = textSize - 1 end end + + elseif (shortMethod == 2) then + detailsFramework:TruncateText(self.button.text, self:GetWidth() - self.icon:GetWidth() - 15) end end end @@ -810,8 +814,8 @@ end --object constructor local onDisableFunc = function(self) self.texture_disabled:Show() - self.texture_disabled:SetVertexColor(0, 0, 0) - self.texture_disabled:SetAlpha(.5) + self.texture_disabled:SetVertexColor(0.1, 0.1, 0.1) + self.texture_disabled:SetAlpha(.834) end local onEnableFunc = function(self) @@ -836,7 +840,7 @@ end self:SetScript("OnEnable", onEnableFunc) end - ---@class df_button : button + ---@class df_button : button, df_scripthookmixin ---@field widget button ---@field tooltip string ---@field shown boolean @@ -852,13 +856,14 @@ end ---@field textcolor any ---@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 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 ---@field Enable fun(self: df_button) enable the button ---@field IsEnabled fun(self: df_button) : boolean returns true if the button is enabled - ---@field SetIcon fun(self: df_button,texture: string, width: number|nil, height: number|nil, layout: string|nil, texcoord: table|nil, overlay: table|nil, textDistance: number|nil, leftPadding: number|nil, textHeight: number|nil, shortMethod: any|nil) + ---@field SetIcon fun(self: df_button,texture: string|number, width: number|nil, height: number|nil, layout: string|nil, texcoord: table|nil, overlay: table|nil, textDistance: number|nil, leftPadding: number|nil, textHeight: number|nil, shortMethod: any|nil) ---@field GetIconTexture fun(self: df_button) : string returns the texture path of the button icon ---@field SetTexture fun(self: df_button, normalTexture: string, highlightTexture: string, pressedTexture: string, disabledTexture: string) set the regular button textures ---@field SetFontFace fun(self: df_button, font: string) set the button font diff --git a/Libs/DF/colors.lua b/Libs/DF/colors.lua index 54b5b33a..0f9b2384 100644 --- a/Libs/DF/colors.lua +++ b/Libs/DF/colors.lua @@ -1,13 +1,12 @@ -do +do local DF = _G ["DetailsFramework"] - if (not DF or not DetailsFrameworkCanLoad) then - return + return end DF.alias_text_colors = DF.alias_text_colors or {} - + local defaultColors = { ["HUNTER"] = {0.67, 0.83, 0.45}, ["WARLOCK"] = {0.58, 0.51, 0.79}, @@ -172,13 +171,13 @@ do ["yellow"] = {1, 1, 0, 1}, ["yellowgreen"] = {0.603922, 0.803922, 0.196078, 1} } - + function DF:GetDefaultColorList() return defaultColors end - + for colorName, colorTable in pairs(defaultColors) do - DF.alias_text_colors [colorName] = colorTable + DF.alias_text_colors[colorName] = colorTable end - + end diff --git a/Libs/DF/definitions.lua b/Libs/DF/definitions.lua index 906d3d9e..6294b934 100644 --- a/Libs/DF/definitions.lua +++ b/Libs/DF/definitions.lua @@ -23,9 +23,14 @@ ---@field RoundedCornerPanelMixin df_roundedcornermixin ---@field Schedules df_schedule ---@field HeaderFunctions df_headerfunctions +---@field KeybindMixin df_keybindmixin ---@field Math df_math ---@field table df_table_functions +---@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 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 +---@field QuickDispatch fun(self:table, callback:function, ...) : any dispatch a function call without errors if the function passed is invalid +---@field CoreDispatch fun(self:table, context:string, callback:function, ...) : any deprecated at this point, use Dispatch instead ---@field GetDefaultBackdropColor fun(self:table) : red, green, blue, alpha return the standard backdrop color used by blizzard on their own frames ---@field Msg fun(self:table, message:string, ...) show a message in the chat frame ---@field MsgWarning fun(self:table, message:string, ...) show a warning message in the chat frame @@ -64,7 +69,17 @@ ---@field NewColor fun(self:table, colorName:string, red:number, green:number, blue:number, alpha:number) ---@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 CreateScrollBox fun(self:table, parent:frame, name:string, refreshFunc:function, data:table, width:number, height:number, lineAmount:number, lineHeight:number, createLineFunc:function?, autoAmount:boolean?, noScroll:boolean?) : df_scrollbox +---@field CreateScrollBox fun(self:table, parent:frame, name:string, refreshFunc:function, data:table, width:number, height:number, lineAmount:number, lineHeight:number, createLineFunc:function?, autoAmount:boolean?, noScroll:boolean?, noBackdrop:boolean?) : df_scrollbox ---@field GetTemplate fun(self:table, templateType:templatetype, 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?) +---@field InstallTemplate fun(self:table, widgetType:string, templateName:string, template:table, parentName:any) : table +---@field NewSpecialLuaEditorEntry fun(self:table, parent:frame, width:number, height:number, member:string?, name:string?, nointent:boolean?, showLineNumbers:boolean?, bNoName:boolean?) : df_luaeditor +---@field PassLoadFilters fun(self:table, loadTable:table, encounterID:number?) : boolean, string +---@field CreateLoadFilterParser fun(self:table, callback:fun(encounterId:number?)) create a helper which will callback when encounterId, spec, talent, role, combatstate changes +---@field CreateSwitch fun(self:table, parent:frame, onSwitch:function, defaultValue:boolean, width:number?, height:number?, leftText:string?, rightText:string?, member:string?, name:string?, colorInverted:boolean?, switchFunc:function?, returnFunc:function?, withLabel:string?, switch_template:table?, label_template:table?) : df_checkbox, df_label? +---@field CreateCheckboxGroup fun(self:table, parent:frame, radioOptions:df_radiooptions[], name:string?, options:table?, anchorOptions:table?) : df_checkboxgroup +---@field CreateRadioGroup fun(self:table, parent:frame, radioOptions:df_radiooptions[], name:string?, options:table?, anchorOptions:table?) : df_radiogroup +---@field ---@field - diff --git a/Libs/DF/dropdown.lua b/Libs/DF/dropdown.lua index 9a69e10a..4f02ff5f 100644 --- a/Libs/DF/dropdown.lua +++ b/Libs/DF/dropdown.lua @@ -1334,7 +1334,7 @@ function DF:CreateNewDropdownFrame(parent, name) child.mouseover = mouseover scroll:SetScrollChild(child) - tinsert(UISpecialFrames, newDropdownFrame.dropdownborder:GetName()) + table.insert(UISpecialFrames, newDropdownFrame.dropdownborder:GetName()) --tinsert(UISpecialFrames, f.dropdownframe:GetName()) --not adding this solves an issue with ConsolePort addon and stackoverflows on Hide... return newDropdownFrame diff --git a/Libs/DF/fw.lua b/Libs/DF/fw.lua index 6b192136..12b6bb67 100644 --- a/Libs/DF/fw.lua +++ b/Libs/DF/fw.lua @@ -1,6 +1,6 @@ -local dversion = 470 +local dversion = 474 local major, minor = "DetailsFramework-1.0", dversion local DF, oldminor = LibStub:NewLibrary(major, minor) @@ -19,7 +19,7 @@ local type = type local unpack = unpack local upper = string.upper local string_match = string.match -local tinsert = _G.tinsert +local tinsert = table.insert local abs = _G.abs local tremove = _G.tremove @@ -1434,6 +1434,45 @@ function DF:GetSpellBookSpells() return spellNamesInSpellBook, spellIdsInSpellBook end +---return a table of passive talents, format: [spellId] = true +---@return {Name: string, ID: number, Texture: any, IsSelected: boolean}[] +function DF:GetAllTalents() + local allTalents = {} + + local configId = C_ClassTalents.GetActiveConfigID() + if (configId) then + local configInfo = C_Traits.GetConfigInfo(configId) + --get the spells from the SPEC from talents + for treeIndex, treeId in ipairs(configInfo.treeIDs) do + local treeNodes = C_Traits.GetTreeNodes(treeId) + for nodeIdIndex, treeNodeID in ipairs(treeNodes) do + local traitNodeInfo = C_Traits.GetNodeInfo(configId, treeNodeID) + if (traitNodeInfo) then + local activeEntry = traitNodeInfo.activeEntry + local entryIds = traitNodeInfo.entryIDs + for i = 1, #entryIds do + local entryId = entryIds[i] --number + local traitEntryInfo = C_Traits.GetEntryInfo(configId, entryId) + local borderTypes = Enum.TraitNodeEntryType + if (traitEntryInfo.type) then -- == borderTypes.SpendCircle + local definitionId = traitEntryInfo.definitionID + local traitDefinitionInfo = C_Traits.GetDefinitionInfo(definitionId) + local spellId = traitDefinitionInfo.overriddenSpellID or traitDefinitionInfo.spellID + local spellName, _, spellTexture = GetSpellInfo(spellId) + if (spellName) then + local talentInfo = {Name = spellName, ID = spellId, Texture = spellTexture, IsSelected = (activeEntry and activeEntry.rank and activeEntry.rank > 0) or false} + allTalents[#allTalents+1] = talentInfo + end + end + end + end + end + end + end + + return allTalents +end + ---return a table where keys are spellIds (number) and the value is true ---@return table function DF:GetAvailableSpells() @@ -1528,7 +1567,7 @@ function DF:GetAvailableSpells() return HasPetSpells() end - --get pet spells from the pet spellbook + --get pet spells from the pet spellbook local numPetSpells = getNumPetSpells() if (numPetSpells) then for i = 1, numPetSpells do @@ -1772,7 +1811,7 @@ end --add a new color name, the color can be query using DetailsFramework:ParseColors(colorName) 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.") + --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) @@ -3475,6 +3514,12 @@ DF.button_templates["OPTIONS_BUTTON_TEMPLATE"] = { backdropbordercolor = {0, 0, 0, 1}, } +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}, +} + --sliders DF.slider_templates = DF.slider_templates or {} DF.slider_templates["OPTIONS_SLIDER_TEMPLATE"] = { @@ -3489,6 +3534,12 @@ DF.slider_templates["OPTIONS_SLIDER_TEMPLATE"] = { thumbcolor = {0, 0, 0, 0.5}, } +---install a template +---@param widgetType string +---@param templateName string +---@param template table +---@param parentName any +---@return table function DF:InstallTemplate(widgetType, templateName, template, parentName) local newTemplate = {} @@ -4986,13 +5037,13 @@ function DF:GetCharacterRaceList() end for i = 1, 100 do - local raceInfo = C_CreatureInfo.GetRaceInfo (i) + 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}) end if IS_WOW_PROJECT_MAINLINE then - local alliedRaceInfo = C_AlliedRaces.GetRaceInfoByID (i) + 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}) end @@ -5005,24 +5056,72 @@ end --get a list of talents for the current spec the player is using --if onlySelected return an index table with only the talents the character has selected --if onlySelectedHash return a hash table with [spelID] = true -function DF:GetCharacterTalents (onlySelected, onlySelectedHash) +function DF:GetCharacterTalents(bOnlySelected, bOnlySelectedHash) local talentList = {} + local version, build, date, tocversion = GetBuildInfo() - for i = 1, 7 do - for o = 1, 3 do - local talentID, name, texture, selected, available = GetTalentInfo (i, o, 1) - if (onlySelectedHash) then - if (selected) then - talentList [talentID] = true - break + if (tocversion >= 70000 and tocversion <= 99999) then + for i = 1, 7 do + for o = 1, 3 do + local talentID, name, texture, selected, available = GetTalentInfo(i, o, 1) + if (bOnlySelectedHash) then + if (selected) then + talentList[talentID] = true + break + end + elseif (bOnlySelected) then + if (selected) then + table.insert(talentList, {Name = name, ID = talentID, Texture = texture, IsSelected = selected}) + break + end + else + table.insert(talentList, {Name = name, ID = talentID, Texture = texture, IsSelected = selected}) end - elseif (onlySelected) then - if (selected) then - tinsert(talentList, {Name = name, ID = talentID, Texture = texture, IsSelected = selected}) - break + end + end + + elseif (tocversion >= 100000) then + if (not bOnlySelected) then + return DF:GetAllTalents() + end + + local configId = C_ClassTalents.GetActiveConfigID() + if (configId) then + local configInfo = C_Traits.GetConfigInfo(configId) + --get the spells from the SPEC from talents + for treeIndex, treeId in ipairs(configInfo.treeIDs) do + local treeNodes = C_Traits.GetTreeNodes(treeId) + + for nodeIdIndex, treeNodeID in ipairs(treeNodes) do + local traitNodeInfo = C_Traits.GetNodeInfo(configId, treeNodeID) + + if (traitNodeInfo) then + local activeEntry = traitNodeInfo.activeEntry + local entryIds = traitNodeInfo.entryIDs + + for i = 1, #entryIds do + local entryId = entryIds[i] --number + local traitEntryInfo = C_Traits.GetEntryInfo(configId, entryId) + local borderTypes = Enum.TraitNodeEntryType + + if (traitEntryInfo.type) then -- == borderTypes.SpendCircle + local definitionId = traitEntryInfo.definitionID + local traitDefinitionInfo = C_Traits.GetDefinitionInfo(definitionId) + local spellId = traitDefinitionInfo.overriddenSpellID or traitDefinitionInfo.spellID + local spellName, _, spellTexture = GetSpellInfo(spellId) + local bIsSelected = (activeEntry and activeEntry.rank and activeEntry.rank > 0) or false + if (spellName and bIsSelected) then + local talentInfo = {Name = spellName, ID = spellId, Texture = spellTexture, IsSelected = true} + if (bOnlySelectedHash) then + talentList[spellId] = talentInfo + else + table.insert(talentList, talentInfo) + end + end + end + end + end end - else - tinsert(talentList, {Name = name, ID = talentID, Texture = texture, IsSelected = selected}) end end end @@ -5030,7 +5129,7 @@ function DF:GetCharacterTalents (onlySelected, onlySelectedHash) return talentList end -function DF:GetCharacterPvPTalents (onlySelected, onlySelectedHash) +function DF:GetCharacterPvPTalents(onlySelected, onlySelectedHash) if (onlySelected or onlySelectedHash) then local talentsSelected = C_SpecializationInfo.GetAllSelectedPvpTalentIDs() local talentList = {} @@ -5294,6 +5393,15 @@ DF.SpecListByClass = { }, } +---return if the specId is a valid spec, it'll return false for specIds from the tutorial area +---@param self table +---@param specId number +function DF:IsValidSpecId(specId) + local _, class = UnitClass("player") + local specs = DF.SpecListByClass[class] + return specs and specs[specId] and true or false +end + --given a class and a specId, return if the specId is a spec from the class passed function DF:IsSpecFromClass(class, specId) return DF.ClassSpecs[class] and DF.ClassSpecs[class][specId] @@ -5808,4 +5916,23 @@ function DF:DebugVisibility(UIObject) local numPoints = UIObject:GetNumPoints() print("Num Points:", numPoints > 0 and "|cFF00FF00" .. numPoints .. "|r" or "|cFFFF00000|r") +end + +local beenchmarkTime = 0 +local beenchmarkEnabled = false +function _G.__benchmark(bNotPrintResult) + if (not beenchmarkEnabled) then + beenchmarkEnabled = true + beenchmarkTime = debugprofilestop() + else + local elapsed = debugprofilestop() - beenchmarkTime + beenchmarkEnabled = false + + if (bNotPrintResult) then + return elapsed + end + + print("Elapsed Time:", elapsed) + return elapsed + end end \ No newline at end of file diff --git a/Libs/DF/header.lua b/Libs/DF/header.lua index a0b7b907..ec74ed27 100644 --- a/Libs/DF/header.lua +++ b/Libs/DF/header.lua @@ -638,8 +638,8 @@ local default_header_options = { ---each column is placed on the right side of the previous column. ---@param parent frame ---@param headerTable table ----@param options table|nil ----@param frameName string|nil +---@param options table? +---@param frameName string? ---@return df_headerframe function detailsFramework:CreateHeader(parent, headerTable, options, frameName) ---create the header frame which is returned by this function @@ -649,6 +649,7 @@ function detailsFramework:CreateHeader(parent, headerTable, options, frameName) detailsFramework:Mixin(newHeader, detailsFramework.OptionsFunctions) detailsFramework:Mixin(newHeader, detailsFramework.HeaderMixin) + options = options or {} newHeader:BuildOptionsTable(default_header_options, options) --set the backdrop and backdrop color following the values in the options table diff --git a/Libs/DF/keybind.lua b/Libs/DF/keybind.lua index d1fdab0b..ba6e1677 100644 --- a/Libs/DF/keybind.lua +++ b/Libs/DF/keybind.lua @@ -4,20 +4,106 @@ if (not detailsFramework or not DetailsFrameworkCanLoad) then return end +--[=[[ + bugs: + -t verificar se esta mostrando o indicador de keybinds repetidas + -t fazer o sort de maneira que fique melhor + -t fazer um indicador dizendo que a keybind esta desabilitada por causa da load condition + -t fazer o debug do puf mostrar as keybinds (string) + - quando iniciar uma edição, fazer um indicador the diga que aquela linha esta esta sendo editada + - transferir o montagem do código seguro das keybinds no puf para o framework + +tried to edit a spell binding: +2x Details/Libs/DF/keybind.lua:1080: attempt to index local 'actionId' (a number value) +[string "@Details/Libs/DF/keybind.lua"]:1160: in function
+[string "=[C]"]: in function `xpcall' +[string "@Details/Libs/DF/fw.lua"]:4864: in function `CoreDispatch' +[string "@Details/Libs/DF/button.lua"]:720: in function
+--]=] + local _ -local CreateFrame = CreateFrame -local GetSpellInfo = GetSpellInfo -local unpack = unpack +local IsShiftKeyDown = _G["IsShiftKeyDown"] +local IsControlKeyDown = _G["IsControlKeyDown"] +local IsAltKeyDown = _G["IsAltKeyDown"] +local CreateFrame = _G["CreateFrame"] +local GetSpellInfo = _G["GetSpellInfo"] +local unpack = unpack ---@diagnostic disable-line + +---@alias actionidentifier string a string in the format of "spell-spellId" or "macro-macroName" or "system-target", etc, used to pass information about the action more easily + +---@class keybind_scroll_data : {key1:string, key2:any, key3:any, key4:string, key5:boolean, key6:number, key7:string} + +---@class df_keybind : table +---@field name string +---@field action string|number +---@field keybind string +---@field macro string +---@field conditions table +---@field icon any + +---@class df_editkeybindframe : frame +---@field bIsEditing boolean +---@field actionIdentifier actionidentifier +---@field conditionsFailLoadReasonText fontstring +---@field keybindTable df_keybind +---@field nameEditBox df_textentry +---@field iconPickerButton df_button +---@field conditionsButton df_button +---@field editMacroEditBox df_luaeditor +---@field cancelButton df_button +---@field saveButton df_button +---@field deleteMacroButton df_button +---@field Disable fun(self:df_editkeybindframe) +---@field Enable fun(self:df_editkeybindframe) + +---@class df_selectkeybindbutton : button +---@field actionIdentifier actionidentifier +---@field keybindTable df_keybind +---@field keybindScrollData keybind_scroll_data + +---@class df_keybindscrollline : frame, df_headerfunctions +---@field bIsSeparator boolean +---@field keybindScrollLine boolean +---@field backgroundTexture texture +---@field highlightTexture texture +---@field separatorTitleText fontstring +---@field spellIconTexture texture +---@field actionNameFontString fontstring +---@field setKeybindButton df_button +---@field clearKeybindButton df_button +---@field editKeybindSettingsButton df_button +---@field SetAsSeparator function + +local keybindPrototype = { + name = "", --a name or alias to call this keybind + action = "", --which action this keybind will do, can be a spellId for spell casting, a macro text or targetting like "target", "focus", "togglemenu" + keybind = "", + macro = "", + conditions = detailsFramework:UpdateLoadConditionsTable({}), + icon = "", +} + +---@type {action: string, keybind: string, icon: string, name: string}[] +local defaultMouseKeybinds = { + {action = "target", name = _G["TARGET"], keybind = "type1", icon = [[Interface\MINIMAP\TRACKING\Target]]}, --default: left mouse button + {action = "togglemenu", name = _G["SLASH_TEXTTOSPEECH_MENU"], keybind = "type2", icon = [[Interface\BUTTONS\UI-GuildButton-PublicNote-Up]]}, --default: right mouse button + {action = "focus", name = _G["FOCUS"], keybind = "type3", icon = [[Interface\MINIMAP\TRACKING\Focus]]} --default: middle mouse button +} + +local defaultMouseKeybindsKV = { + ["target"] = defaultMouseKeybinds[1], + ["togglemenu"] = defaultMouseKeybinds[2], + ["focus"] = defaultMouseKeybinds[3], +} ---@class df_keybindscroll : df_scrollbox ---@field UpdateScroll fun(self:df_keybindscroll) ----@class df_keybinddata : table - ---@class df_keybindframe : frame, df_optionsmixin ---@field options table ---@field data table ---@field keybindData table +---@field keybindScrollData keybind_scroll_data ---@field Header df_headerframe ---@field actionId number? the actionId is the spell Id or an actionId or a macro text ---@field button button? the button which got clicked to start editing a keybind @@ -25,273 +111,108 @@ local unpack = unpack ---@field bIsKeybindFrame boolean ---@field keybindScroll df_keybindscroll ---@field keybindListener frame +---@field editKeybindFrame df_editkeybindframe ---@field callback function +---@field ClearKeybind fun(self:button, buttonPresed:string, actionIdentifier:actionidentifier, keybindTable:any) ---@field CreateKeybindScroll fun(self:df_keybindframe) ---@field CreateKeybindListener fun(self:df_keybindframe) +---@field CreateEditPanel fun(self:df_keybindframe) +---@field CreateKeybindScrollLine fun(self:df_keybindframe, index:number) +---@field DeleteMacro fun(self:df_keybindframe) +---@field FindKeybindTable fun(self:df_keybindframe, keybindType:string, actionId:any, actionIdentifier:actionidentifier?) : df_keybind?, number? +---@field GetEditPanel fun(self:df_keybindframe) : df_editkeybindframe +---@field GetPressedModifiers fun() : string ---@field GetListeningActionId fun(self:df_keybindframe) : number ----@field GetListeningState fun(self:df_keybindframe) : boolean, number, button ----@field GetKeybindData fun(self:df_keybindframe) : df_keybinddata +---@field GetListeningState fun(self:df_keybindframe) : boolean, any, button, keybind_scroll_data +---@field GetKeybindData fun(self:df_keybindframe) : df_keybind[] ---@field GetKeybindListener fun(self:df_keybindframe) : frame ---@field GetKeybindScroll fun(self:df_keybindframe) : df_keybindscroll ---@field GetKeybindCallback fun(self:df_keybindframe):function +---@field GetKeybindModifiers fun(keybind:string) : string +---@field GetKeybindTypeAndActionFromIdentifier fun(self:df_keybindframe, actionIdentifier:actionidentifier) : string, any ---@field IsListening fun(self:df_keybindframe) : boolean ----@field OnKeybindChanged fun(self:df_keybindframe, actionId:number, keybind:string?) ----@field SaveKeybind fun(self:df_keybindframe, key:string) ----@field SetListeningState fun(self:df_keybindframe, value:boolean, actionId:number?, button:button?) +---@field IsEditingKeybindSettings fun(self:df_keybindframe) : boolean, string, df_keybind +---@field IsKeybindActionMacro fun(self:df_keybindframe, actionId:any) : boolean +---@field CallKeybindChangeCallback fun(self:df_keybindframe, type:string, keybindTable:df_keybind?, keybindPressed:string?, removedIndex:number?, macroText:string?) +---@field OnKeybindNameChange fun(self:df_keybindframe, name:string) +---@field OnKeybindMacroChange fun(self:df_keybindframe, macroText:string) +---@field OnKeybindIconChange fun(self:df_keybindframe, iconTexture:string) +---@field OnUserClickedToChooseKeybind fun(self:df_keybindframe, button:button, actionIdentifier:actionidentifier, keybindTable:df_keybind|false) +---@field OnUserPressedKeybind fun(self:df_keybindframe, key:string) +---@field SaveKeybindToKeybindData fun(self:df_keybindframe, actionId:any, pressedKeybind:any, bJustCreated:boolean) +---@field SetClearButtonsEnabled fun(self:df_keybindframe, enabled:boolean) +---@field SetEditButtonsEnabled fun(self:df_keybindframe, enabled:boolean) +---@field SetListeningState fun(self:df_keybindframe, value:boolean, actionIdentifier:actionidentifier?, button:button?, keybindScrollData:keybind_scroll_data?) ---@field SetKeybindData fun(self:df_keybindframe, keybindData:table) ---@field SetKeybindCallback fun(self:df_keybindframe, callback:function) +---@field StartEditingKeybindSettings fun(self:frame, button:string, actionIdentifier:actionidentifier, keybindTable:df_keybind) +---@field StopEditingKeybindSettings fun(self:df_keybindframe) ---@field SwitchSpec fun(self:button, button:string, newSpecId:number) ----@field CreateKeybindScrollLine fun(self:df_keybindframe, index:number) ----@field ClearKeybind fun(self:df_keybindframe, actionId:number) ----@field - ----@class keybind_scroll_data : table ----@field key1 spellname ----@field key2 textureid ----@field key3 any ----@field key4 string keybind ----@field key5 boolean is available ----@field key6 number sort value detailsFramework:NewColor("BLIZZ_OPTIONS_COLOR", 1, 0.8196, 0, 1) -local DARK_BUTTON_TEMPLATE = detailsFramework:InstallTemplate("button", "DARK_BUTTON_TEMPLATE", {backdropcolor = {.1, .1, .1, .7}}, "OPTIONS_BUTTON_TEMPLATE") +local DARK_BUTTON_TEMPLATE = detailsFramework:InstallTemplate("button", "DARK_BUTTON_TEMPLATE", {backdropcolor = {.1, .1, .1, .98}}, "OPTIONS_BUTTON_TEMPLATE") + +---only called from OnUserPressedKeybind() when the a keybindTable is not found for the action +---@return df_keybind +local createNewKeybindTable = function(name, keybind, macro, actionId, iconTexture) + ---@type df_keybind + local newMacroTable = detailsFramework.table.copy({}, keybindPrototype) + newMacroTable.name = name or "My New Macro" --if a name isn't passed, it's a macro + newMacroTable.keybind = keybind or "" + newMacroTable.macro = macro or "" + newMacroTable.action = actionId + newMacroTable.icon = iconTexture or "" + return newMacroTable +end + +---return a number representing the sort order of a spell +---@param keybindData any +---@param spellName string +---@param bIsAvailable any +---@return number +local getSpellSortOrder = function(keybindData, spellName, bIsAvailable) + local sortScore = 0 + + if (not bIsAvailable) then + sortScore = sortScore + 5000 + end + + if (not keybindData) then + sortScore = sortScore + 300 + end + + sortScore = sortScore + string.byte(spellName) + return sortScore +end local default_options = { - width = 550, + width = 580, height = 500, - scroll_width = 550 - 10, - scroll_height = 500 - 20, + edit_width = 400, + edit_height = 0, + scroll_width = 580, + scroll_height = 480, amount_lines = 18, line_height = 26, show_spells = true, show_unitcontrols = true, + show_macros = true, can_modify_keybind_data = true, --if false, won't change the data table passed on the constructor or the one returned by GetKeybindData } local headerTable = { {text = "", width = 34}, --spell icon - {text = "Ability Name", width = 200}, + {text = "", width = 200}, {text = "Keybind", width = 260}, {text = "Clear", width = 40}, + {text = "Edit", width = 40}, } local headerOptions = { padding = 2, + backdrop_color = {0, 0, 0, 0}, } ----@type {name: string, keybind: string, icon: string, localizedName: string}[] -local unitControlKeybinds = { - {name = "target", localizedName = TARGET, keybind = "type1", icon = [[Interface\MINIMAP\TRACKING\Target]]}, --default: left mouse button - {name = "menu", localizedName = "menu", keybind = "type2", icon = [[Interface\BUTTONS\UI-GuildButton-PublicNote-Up]]}, --default: right mouse button - {name = "focus", localizedName = FOCUS, keybind = "type3", icon = [[Interface\MINIMAP\TRACKING\Focus]]} --default: middle mouse button -} - -local defaultSpecKeybindList = { - ["EVOKER"] = { - [1467] = { - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [1468] = { - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [1473] = { --aug - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - }, - - ["DEMONHUNTER"] = { - [577] = {--> havoc demon hunter - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [581] = {--> vengeance demon hunter - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - }, - - ["DEATHKNIGHT"] = { - [250] = { --> blood dk - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [251] = { --> frost dk - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [252] = { --> unholy dk - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - }, - - ["WARRIOR"] = { - [71] = { --> warrior arms - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [72] = { --> warrior fury - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [73] = { --> warrior protect - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - }, - - ["MAGE"] = { - [62] = { --> mage arcane - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - [63] = { --> mage fire - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - [64] = { --> mage frost - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - }, - - ["ROGUE"] = { - [259] = { --> rogue assassination - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - [260] = { --> rogue combat - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - [261] = { --> rogue sub - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - }, - - ["DRUID"] = { - [102] = { --> druid balance - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_dispel", actiontext = ""}, - }, - [103] = { --> druid feral - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [104] = { --> druid guardian - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [105] = { --> druid resto - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_dispel", actiontext = ""}, - }, - }, - - ["HUNTER"] = { - [253] = { --> hunter bm - {key = "type1", action = "_target", actiontext = ""}, - }, - [254] = { --> hunter marks - {key = "type1", action = "_target", actiontext = ""}, - }, - [255] = { --> hunter survivor - {key = "type1", action = "_target", actiontext = ""}, - }, - }, - - ["SHAMAN"] = { - [262] = { --> shaman elemental - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - [263] = { --> shamel enhancement - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - [264] = { --> shaman resto - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - }, - - ["PRIEST"] = { - [256] = { --> priest disc - {key = "type1", action = "_target", actiontext = ""}, - }, - [257] = { --> priest holy - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_dispel", actiontext = ""}, - }, - [258] = { --> priest shadow - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - }, - }, - - ["WARLOCK"] = { - [265] = { --> warlock aff - {key = "type1", action = "_target", actiontext = ""}, - }, - [266] = { --> warlock demo - {key = "type1", action = "_target", actiontext = ""}, - }, - [267] = { --> warlock destro - {key = "type1", action = "_target", actiontext = ""}, - }, - }, - - ["PALADIN"] = { - [65] = { --> paladin holy - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_dispel", actiontext = ""}, - }, - [66] = { --> paladin protect - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [70] = { --> paladin ret - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - }, - - ["MONK"] = { - [268] = {--> monk bm - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [269] = {--> monk ww - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_interrupt", actiontext = ""}, - {key = "type3", action = "_taunt", actiontext = ""}, - }, - [270] = {--> monk mw - {key = "type1", action = "_target", actiontext = ""}, - {key = "type2", action = "_dispel", actiontext = ""}, - }, - }, -} local ignoredKeys = { ["LSHIFT"] = true, @@ -302,6 +223,7 @@ local ignoredKeys = { ["RALT"] = true, ["UNKNOWN"] = true, } + local mouseButtonToClickType = { ["LeftButton"] = "type1", ["RightButton"] = "type2", @@ -320,88 +242,12 @@ local mouseButtonToClickType = { ["Button15"] = "type15", ["Button16"] = "type16", } -local clickTypeToMouseButton = { - ["type1"] = "LeftButton", - ["type2"] = "RightButton", - ["type3"] = "MiddleButton", - ["type4"] = "Button4", - ["type5"] = "Button5", - ["type6"] = "Button6", - ["type7"] = "Button7", - ["type8"] = "Button8", - ["type9"] = "Button9", - ["type10"] = "Button10", - ["type11"] = "Button11", - ["type12"] = "Button12", - ["type13"] = "Button13", - ["type14"] = "Button14", - ["type15"] = "Button15", - ["type16"] = "Button16", -} - -local clickTypeAlias = { - ["type1"] = "Left Mouse Button", - ["type2"] = "Right Mouse Button", - ["type3"] = "Middle Mouse Button", - ["type4"] = "Mouse Button 4", - ["type5"] = "Mouse Button 5", - ["type6"] = "Mouse Button 6", - ["type7"] = "Mouse Button 7", - ["type8"] = "Mouse Button 8", - ["type9"] = "Mouse Button 9", - ["type10"] = "Mouse Button 10", - ["type11"] = "Mouse Button 11", - ["type12"] = "Mouse Button 12", - ["type13"] = "Mouse Button 13", - ["type14"] = "Mouse Button 14", - ["type15"] = "Mouse Button 15", - ["type16"] = "Mouse Button 16", -} - -local tauntList = { - ["DEATHKNIGHT"] = 56222, --Dark Command - ["DEMONHUNTER"] = 185245, --Torment - ["WARRIOR"] = 355, --Taunt - ["PALADIN"] = 62124, --Hand of Reckoning - ["MONK"] = 115546, --Provoke - ["DRUID"] = 6795, --Growl -} - -local interruptList = { - ["DEATHKNIGHT"] = 47528, --Mind Freeze - ["DEMONHUNTER"] = 183752, --Consume Magic - ["WARRIOR"] = 6552, --Pummel - ["PALADIN"] = 96231, --Rebuke - ["MONK"] = 116705, --Spear Hand Strike - ["HUNTER"] = 147362, --Counter Shot - ["MAGE"] = 2139, --Counterspell - ["DRUID"] = 106839, --Skull Bash - - ["ROGUE"] = 1766, --Kick - ["SHAMAN"] = 57994, --Wind Shear - ["PRIEST"] = 15487, --Silence -} - -local dispelList = { - ["PALADIN"] = {[65] = 4987, [66] = 213644, [70] = 213644}, --Cleanse - Cleanse Toxins - so holy tem 'cleanse' tank e dps tem o toxins - ["MONK"] = 115450, --Detox - ["DRUID"] = {[102] = 2782, [103] = 2782, [104] = 2782, [105] = 88423}, --Nature's Cure - Remove Corruption -so restoration tem o natures cure - ["SHAMAN"] = {[262] = 51886, [263] = 51886, [264] = 77130}, --elemental melee Cleanse Spirit - resto Purify Spirit - ["PRIEST"] = {[256] = 527, [257] = 527, [258] = 213634}, --Purify holy disc - Purify Disease shadow -} - -local lock_textentry = { - ["_target"] = true, - ["_taunt"] = true, - ["_interrupt"] = true, - ["_dispel"] = true, - ["_spell"] = false, - ["_macro"] = false, -} local roundedCornerPreset = { roundness = 5, - color = {.075, .075, .075, 0.98}, - border_color = {.05, .05, .05, 0}, + color = {.075, .075, .075, 1}, + border_color = {.05, .05, .05, 1}, + horizontal_border_size_offset = 8, } --> helpers @@ -420,6 +266,29 @@ local getMainFrame = function(UIObject) end end +local setAsSeparator = function(line, bIsSeparator, titleText) + if (bIsSeparator) then + line.spellIconTexture:Hide() + line.actionNameFontString:Hide() + line.setKeybindButton:Hide() + line.clearKeybindButton:Hide() + line.editKeybindSettingsButton:Hide() + line.separatorTitleText:Show() + line.separatorTitleText:SetText(titleText) + line.bIsSeparator = true + line.backgroundTexture:Hide() + else + line.spellIconTexture:Show() + line.actionNameFontString:Show() + line.setKeybindButton:Show() + line.clearKeybindButton:Show() + line.editKeybindSettingsButton:Show() + line.separatorTitleText:Hide() + line.bIsSeparator = false + line.backgroundTexture:Show() + end +end + ---@class df_keybindmixin detailsFramework.KeybindMixin = { bIsListening = false, @@ -452,10 +321,14 @@ detailsFramework.KeybindMixin = { ---@param value boolean ---@param actionId number? ---@param button button? - SetListeningState = function(self, value, actionId, button) + SetListeningState = function(self, value, actionId, button, keybindScrollData) self.bIsListening = value self.actionId = actionId self.button = button + self.keybindScrollData = keybindScrollData + + self:SetClearButtonsEnabled(not value) + self:SetEditButtonsEnabled(not value) end, ---get the listening state @@ -463,8 +336,9 @@ detailsFramework.KeybindMixin = { ---@return boolean ---@return number ---@return button + ---@return keybind_scroll_data GetListeningState = function(self) - return self.bIsListening, self.actionId, self.button + return self.bIsListening, self.actionId, self.button, self.keybindScrollData end, ---return the frame which wait for keybinds @@ -498,45 +372,214 @@ detailsFramework.KeybindMixin = { ---callback from the clear button ---@param self button ---@param button any - ---@param keyBindFrame df_keybindframe - ClearKeybind = function(self, button, actionId, keyBindFrame) - local keybindData = keyBindFrame:GetKeybindData() - keybindData[actionId] = nil - keyBindFrame:OnKeybindChanged(actionId, nil) + ---@param actionIdentifier string + ---@param keybindTable any + ClearKeybind = function(self, button, actionIdentifier, keybindTable) --~clear + if (not keybindTable) then + return + end + + ---@type df_keybindframe + local keyBindFrame = getMainFrame(self) + + local keybindType, actionId = keyBindFrame:GetKeybindTypeAndActionFromIdentifier(actionIdentifier) + local _, index = keyBindFrame:FindKeybindTable(keybindType, actionId, actionIdentifier) + + if (index) then + if (keybindType == "macro") then + keybindTable.keybind = "" + else + if (keyBindFrame.options.can_modify_keybind_data) then + local keybindData = keyBindFrame:GetKeybindData() + table.remove(keybindData, index) + end + keyBindFrame:CallKeybindChangeCallback("removed", nil, nil, index) + end + end + + local bIsEditingKeybind = keyBindFrame:IsEditingKeybindSettings() + if (bIsEditingKeybind) then + keyBindFrame:StopEditingKeybindSettings() + end + local keybindScroll = keyBindFrame:GetKeybindScroll() keybindScroll:UpdateScroll() end, + ---@param self df_keybindframe + DeleteMacro = function(self) + local bIsEditingKeybind, actionIdentifier, keybindTable = self:IsEditingKeybindSettings() + if (not bIsEditingKeybind) then + return + end + + if (not self:IsKeybindActionMacro(keybindTable.action)) then + return + end + + local _, index = self:FindKeybindTable("macro", keybindTable.action, actionIdentifier) + + if (index) then + if (self.options.can_modify_keybind_data) then + local keybindData = self:GetKeybindData() + table.remove(keybindData, index) + end + + self:CallKeybindChangeCallback("removed", nil, nil, index) + end + + self:StopEditingKeybindSettings() + + local keybindScroll = self:GetKeybindScroll() + keybindScroll:UpdateScroll() + end, + + ---return a string with the modifiers of a keybind + ---@param keybind string + ---@return string + GetKeybindModifiers = function(keybind) + local modifier = "" + keybind = string.upper(keybind) + + if (keybind:find("SHIFT-")) then + modifier = "SHIFT-" + end + + if (keybind:find("CTRL-")) then + modifier = modifier .. "CTRL-" + end + + if (keybind:find("ALT-")) then + modifier = modifier .. "ALT-" + end + + return modifier + end, + + ---return a string with the modifiers of the key pressed by the player + ---@return string + GetPressedModifiers = function() + return (IsShiftKeyDown() and "SHIFT-" or "") .. (IsControlKeyDown() and "CTRL-" or "") .. (IsAltKeyDown() and "ALT-" or "") + end, + ---comment ---@param self df_keybindframe - ---@param key any - SaveKeybind = function(self, key) --where this is called? : from OnClickSetKeybindButton and from OnKeyDown() script + ---@param keybindTable df_keybind + ---@param pressedKeybind any + ---@param bKeybindJustCreated boolean + SaveKeybindToKeybindData = function(self, keybindTable, pressedKeybind, bKeybindJustCreated) + local keybindData = self:GetKeybindData() --from savedVariables + + --if the keybindTable was created by the function which called this function, then need to add the keybind into the saved variables table + if (bKeybindJustCreated) then + table.insert(keybindData, keybindTable) + end + + keybindTable.keybind = pressedKeybind + end, + + ---return the keybindData table if exists + ---@param self df_keybindframe + ---@param keybindType string + ---@param actionId any + ---@param actionIdentifier actionidentifier? + ---@return df_keybind?, number? + FindKeybindTable = function(self, keybindType, actionId, actionIdentifier) + local keybindData = self:GetKeybindData() + + if (keybindType == "spell" or keybindType == "system") then + for i = 1, #keybindData do + local keybindTable = keybindData[i] + if (keybindTable.action == actionId) then + return keybindTable, i + end + end + end + + if (keybindType == "macro") then + for i = 1, #keybindData do + local keybindTable = keybindData[i] + if (keybindTable.action == actionIdentifier) then + return keybindTable, i + end + end + end + end, + + ---comment + ---@param self df_keybindframe + ---@param actionIdentifier any + ---@return string + ---@return string|number + GetKeybindTypeAndActionFromIdentifier = function(self, actionIdentifier) + ---@type string, string + local keybindType, actionId = actionIdentifier:match("([^%-]+)%-(.+)") + if (keybindType == "spell") then + return keybindType, tonumber(actionId) and tonumber(actionId) or 0 + end + return keybindType, actionId + end, + + ---when the user selected a keybind for an action, this function is called + ---@param self df_keybindframe + ---@param keyPressed any keyboard or mouse key to be used to perform the choosen action + OnUserPressedKeybind = function(self, keyPressed) --called from OnUserClickedToChooseKeybind and from OnKeyDown() script --if the player presses a control key, ignore it - if (ignoredKeys[key]) then + if (ignoredKeys[keyPressed]) then return end local keybindListener = self:GetKeybindListener() --exit the process if 'esc' is pressed - if (key == "ESCAPE") then + if (keyPressed == "ESCAPE") then self:SetListeningState(false) keybindListener:Hide() self:SetScript("OnKeyDown", nil) return end - local modifier = (IsShiftKeyDown() and "SHIFT-" or "") .. (IsControlKeyDown() and "CTRL-" or "") .. (IsAltKeyDown() and "ALT-" or "") - local newKeybind = modifier .. key - local bIsListening, actionId, frameButton = self:GetListeningState() + local modifiers = self:GetPressedModifiers() + local pressedKeybind = modifiers .. keyPressed + local bIsListening, actionIdentifier, button, keybindScrollData = self:GetListeningState() + local bKeybindJustCreated = false - if (self.options.can_modify_keybind_data) then - ---@type table - local keybindData = self:GetKeybindData() --from savedVariables - keybindData[actionId] = newKeybind + --keybindType can be 'macro', 'spell' or 'system' + --actionId can be a spellId, a macro name or some other action like 'target' 'focus' 'togglemenu' + local keybindType, actionId = self:GetKeybindTypeAndActionFromIdentifier(actionIdentifier) + local keybindTable = self:FindKeybindTable(keybindType, actionId, actionIdentifier) + + if (not keybindTable) then + local iconTexture = keybindScrollData[2] + --create a new keybindTable + if (keybindType == "spell") then + local spellId = actionId + local spellName = GetSpellInfo(spellId) + if (spellName) then + --actionId is the spellId + keybindTable = createNewKeybindTable(spellName, pressedKeybind, "", actionId, iconTexture) + end + + elseif (keybindType == "system") then + local defaultKeybind = defaultMouseKeybindsKV[actionId] + --actionId is an action like 'target' 'focus' 'togglemenu' + keybindTable = createNewKeybindTable(defaultKeybind.name, pressedKeybind, "", actionId, iconTexture) + + elseif (keybindType == "macro") then + local macroName = "New Macro" + --actionId is the word 'macro' + keybindTable = createNewKeybindTable(macroName, pressedKeybind, "/say hi", "macro", iconTexture) + end + + bKeybindJustCreated = true end - self:OnKeybindChanged(actionId, newKeybind) + if (self.options.can_modify_keybind_data) then + --if the options for this frame allows it to change the keybind in the addon savedVariables, then do it + self:SaveKeybindToKeybindData(keybindTable, pressedKeybind, bKeybindJustCreated) + end + + self:CallKeybindChangeCallback("modified", keybindTable, pressedKeybind) self:SetListeningState(false) self:SetScript("OnKeyDown", nil) @@ -548,141 +591,284 @@ detailsFramework.KeybindMixin = { keybindScroll:UpdateScroll() end, - ---callback for the OnClickSetKeybindButton function on the scrollframe - ---@param self button + ---callback for when the user click in to define a keybind to an action + ---@param self df_selectkeybindbutton ---@param button any - ---@param actionId number - ---@param keyBindFrame df_keybindframe - OnClickSetKeybindButton = function(self, button, actionId, keyBindFrame) + ---@param actionIdentifier actionidentifier + ---@param keybindTable df_keybindframe + OnUserClickedToChooseKeybind = function(self, button, actionIdentifier, keybindTable) + ---@type df_keybindframe + local keyBindFrame = getMainFrame(self) local bIsListening, _, frameButton = keyBindFrame:GetListeningState() - --if the listener is already listening for a keybind while the player clicks on another OnClickSetKeybindButton button, then cancel the previous listener + --if the listener is already listening for a keybind while the player clicks on another OnUserClickedToChooseKeybind button, then cancel the previous listener if (bIsListening and (self == frameButton)) then --if the frame is already listening, it could be a mouse click to set the keybind local clickType = mouseButtonToClickType[button] - print("mouse click:", button, clickType) - keyBindFrame:SaveKeybind(clickType) + keyBindFrame:OnUserPressedKeybind(clickType) return end - keyBindFrame:SetListeningState(true, actionId, self) - keyBindFrame:SetScript("OnKeyDown", keyBindFrame.SaveKeybind) + bIsListening = true + + local keybindScrollData = self.keybindScrollData + keyBindFrame:SetListeningState(bIsListening, actionIdentifier, self, keybindScrollData) + keyBindFrame:SetScript("OnKeyDown", keyBindFrame.OnUserPressedKeybind) local keybindListener = keyBindFrame:GetKeybindListener() keybindListener:ClearAllPoints() keybindListener:SetPoint("bottom", self, "top", 0, 0) keybindListener:Show() + + local bIsEditingKeybind = keyBindFrame:IsEditingKeybindSettings() + if (bIsEditingKeybind) then + keyBindFrame:StopEditingKeybindSettings() + end + end, + + SetClearButtonsEnabled = function(self, bIsEnabled) + local keybindScroll = self:GetKeybindScroll() + local lines = keybindScroll:GetLines() + for i = 1, #lines do + local line = lines[i] + if (bIsEnabled) then + --can only set enabled if the keybind isn't empty + if (line.setKeybindButton.text ~= "") then + line.clearKeybindButton:Enable() + end + else + line.clearKeybindButton:Disable() + end + end + end, + + SetEditButtonsEnabled = function(self, bIsEnabled) + local keybindScroll = self:GetKeybindScroll() + local lines = keybindScroll:GetLines() + for i = 1, #lines do + local line = lines[i] + if (bIsEnabled) then + --can only set enabled if the keybind isn't empty + if (line.setKeybindButton.text ~= "") then + line.editKeybindSettingsButton:Enable() + end + else + line.editKeybindSettingsButton:Disable() + end + end end, RefreshKeybindScroll = function(self, scrollData, offset, totalLines) --~refresh local keyBindFrame = getMainFrame(self) + ---@type table + local repeatedKeybinds = {} + + ---@cast scrollData keybind_scroll_data[] + + --build a list of repeated keybinds + for index = 1, #scrollData do + local keybindScrollData = scrollData[index] + local actionName, iconTexture, actionId, keybindData, bIsAvailable = unpack(keybindScrollData) + ---@cast keybindData df_keybind + + if (bIsAvailable) then + if (type(keybindData) == "table" and keybindData.keybind and keybindData.keybind ~= "") then + repeatedKeybinds[keybindData.keybind] = repeatedKeybinds[keybindData.keybind] or {} + table.insert(repeatedKeybinds[keybindData.keybind], keybindData) + end + end + end + + --local bIsListening = keyBindFrame:GetListeningState() + --local bIsEditingKeybind = keyBindFrame:IsEditingKeybindSettings() + + local lastKeybindActionType = "" + + --refresh the scroll bar for i = 1, totalLines do local index = i + offset + ---@type keybind_scroll_data local keybindScrollData = scrollData[index] if (keybindScrollData) then local line = self:GetLine(i) - --actionId can be a actionId or an action name, e.g. "target" - ---@type string, number, number, string, boolean - local actionName, iconTexture, actionId, keybind, bIsAvailable = unpack(keybindScrollData) + ---@type string, number, any, df_keybind|false, boolean, number, string + local actionName, iconTexture, actionId, keybindTable, bIsAvailable, sortNumber, actionIdentifier = unpack(keybindScrollData) - --if the keybind isn't set, it is an empty string - local keyBindText = keybind - keyBindText = keyBindText:gsub("type1", "Left Mouse Button") - keyBindText = keyBindText:gsub("type2", "Right Mouse Button") - keyBindText = keyBindText:gsub("type3", "Middle Mouse Button") - keyBindText = keyBindText:gsub("type4", "Mouse Button 4") - keyBindText = keyBindText:gsub("type5", "Mouse Button 5") - keyBindText = keyBindText:gsub("%-", " - ") + if (actionName == "@separator") then + line:SetAsSeparator(true, iconTexture) + else + line:SetAsSeparator(false) + --if the keybindData doesn't exists, means the user did not set a keybind for this action yet + --in this case keybindData is a false boolean + --keydindText is the text showing which keyboard or mouse button need to be pressed to activate the action + --if the keybind isn't set, use an empty string + local keydindText = keybindTable and keybindTable.keybind or "" - line.setKeybindButton.text = keyBindText - line.setKeybindButton:SetClickFunction(keyBindFrame.OnClickSetKeybindButton, actionId, keyBindFrame, "left") - line.setKeybindButton:SetClickFunction(keyBindFrame.OnClickSetKeybindButton, actionId, keyBindFrame, "right") + keydindText = keydindText:gsub("type1", _G["LEFT_BUTTON_STRING"]) + keydindText = keydindText:gsub("type2", _G["RIGHT_BUTTON_STRING"]) + keydindText = keydindText:gsub("type3", _G["MIDDLE_BUTTON_STRING"]) - line.clearKeybindButton:SetClickFunction(keyBindFrame.ClearKeybind, actionId, keyBindFrame) + if (keydindText:match("type%d")) then + local buttonId = keydindText:match("type(%d)") + buttonId = tonumber(buttonId) + if (buttonId) then + local buttonName = _G["BUTTON_" .. buttonId .. "_STRING"] + if (buttonName and type(buttonName) == "string") then + keydindText = keydindText:gsub("type" .. buttonId, buttonName) + end + end + end - line.spellIconTexture:SetTexture(iconTexture) - line.spellIconTexture:SetDesaturated(not bIsAvailable) - line.spellIconTexture:SetTexCoord(.1, .9, .1, .9) - line.spellNameFontString:SetText(actionName) + keydindText = keydindText:gsub("%-", " - ") - --action - --line.ActionDrop:SetFixedParameter(index) - --line.ActionDrop:Select(keybindData.action) + line.setKeybindButton.text = keydindText - --action text - --line.ActionText.text = keybind --keybindData.actiontext - --line.ActionText:SetEnterFunction(set_action_text, index) - --line.ActionText.CurIndex = index + --start editing keybind button + line.setKeybindButton:SetClickFunction(keyBindFrame.OnUserClickedToChooseKeybind, actionIdentifier, keybindTable, "left") + line.setKeybindButton:SetClickFunction(keyBindFrame.OnUserClickedToChooseKeybind, actionIdentifier, keybindTable, "right") - if (lock_textentry[keybindScrollData.action]) then - --line.ActionText:Disable() - else - --line.ActionText:Enable() - end + --clear keybind button + if (keydindText ~= "") then + line.clearKeybindButton:Enable() + line.clearKeybindButton:SetClickFunction(keyBindFrame.ClearKeybind, actionIdentifier, keybindTable) + line.editKeybindSettingsButton:Enable() + line.editKeybindSettingsButton:SetClickFunction(keyBindFrame.StartEditingKeybindSettings, actionIdentifier, keybindTable) + else + line.clearKeybindButton:Disable() + line.editKeybindSettingsButton:Disable() + end + + local setKeybindButtonWidget = line.setKeybindButton.widget + setKeybindButtonWidget.keybindScrollData = keybindScrollData + + line.spellIconTexture:SetTexture(iconTexture) + + if (not bIsAvailable) then + line.spellIconTexture:SetDesaturated(true) + line.setKeybindButton.widget:SetColor(0, 0, 0, 0.1) + detailsFramework:SetFontColor(line.actionNameFontString, "gray") + else + line.spellIconTexture:SetDesaturated(false) + line.setKeybindButton.widget:SetColor(unpack(roundedCornerPreset.color)) + detailsFramework:SetFontColor(line.actionNameFontString, "BLIZZ_OPTIONS_COLOR") + end + + line.spellIconTexture:SetTexCoord(.1, .9, .1, .9) + line.actionNameFontString:SetText(actionName) + + line.setKeybindButton.widget:SetBorderCornerColor(0, 0, 0, 0) + + --check for repeated keybind + if (keybindTable and bIsAvailable) then + local keybind = keybindTable.keybind + local keybindTables = repeatedKeybinds[keybind] + if (keybindTables and #keybindTables > 1) then + line.setKeybindButton.widget:SetBorderCornerColor(1, .68, 0, 1) + end + end + end end end end, - change_key_action = function(self, keybindIndex, value) - local keyBindFrame = getMainFrame(self) - local keybind = keyBindFrame.CurrentKeybindEditingSet[keybindIndex] - keybind.action = value - keyBindFrame.keybindScroll:UpdateScroll() - end, - - set_action_on_espace_press = function (textentry, capsule) - local keyBindFrame = getMainFrame(textentry) - capsule = capsule or textentry.MyObject - local keybind = keyBindFrame.CurrentKeybindEditingSet[capsule.CurIndex] - textentry:SetText (keybind.actiontext) - end, - - fill_action_dropdown = function(dropdownObject) - local keyBindFrame = getMainFrame(dropdownObject) - - return { - {value = "_target", label = "Target", onclick = keyBindFrame.change_key_action, desc = "Target the unit"}, - --{value = "_taunt", label = "Taunt", onclick = keyBindFrame.change_key_action, desc = "Cast the taunt spell for your class\n\n|cFFFFFFFFSpell: " .. taunt}, - --{value = "_interrupt", label = "Interrupt", onclick = keyBindFrame.change_key_action, desc = "Cast the interrupt spell for your class\n\n|cFFFFFFFFSpell: " .. interrupt}, - --{value = "_dispel", label = "Dispel", onclick = keyBindFrame.change_key_action, desc = "Cast the interrupt spell for your class\n\n|cFFFFFFFFSpell: " .. dispel}, - {value = "_spell", label = "Cast Spell", onclick = keyBindFrame.change_key_action, desc = "Type the spell name in the text box"}, - {value = "_macro", label = "Macro", onclick = keyBindFrame.change_key_action, desc = "Type your macro in the text box"}, - } - end, - ---run when the mouse enters a scroll line + ---@param self df_keybindscrollline OnEnterScrollLine = function(self) - local highlightTexture = self.highlightTexture - if (not highlightTexture) then - highlightTexture = self:GetParent().highlightTexture + local keyBindFrame = getMainFrame(self) + local editPanel = keyBindFrame:GetEditPanel() + editPanel.conditionsFailLoadReasonText:SetText("") + + if (self.bIsSeparator) then + return + end + + if (not self.keybindScrollLine) then + --when the mouse enters a child frame, the self is the child frame, not the scroll line + self = self:GetParent() ---@diagnostic disable-line getting the parent from df_keybindscrollline would result in type frame making invalid convertion + ---@cast self df_keybindscrollline + end + + self.highlightTexture:Show() + + --if the keybind is a macro, preview the macro text in the edit panel's lua edit box + local bIsEditingKeybind = keyBindFrame:IsEditingKeybindSettings() + + if (not bIsEditingKeybind) then + local keybindScrollData = self.setKeybindButton.widget["keybindScrollData"] + if (keybindScrollData) then + local actionName, iconTexture, actionId, keybindTable, bIsAvailable, sortNumber, actionIdentifier = unpack(keybindScrollData) + ---@cast keybindTable df_keybind + if (actionName ~= "@separator" and keybindTable) then + if (keybindTable.macro and keybindTable.macro ~= "") then + ---@type df_editkeybindframe + editPanel.editMacroEditBox:SetText(keybindTable.macro) + end + + local loadCondition = keybindTable.conditions + local bCanLoad, reason = detailsFramework:PassLoadFilters(loadCondition) + + if (not bCanLoad) then + editPanel.conditionsFailLoadReasonText:SetText("This keybind can't be loaded because it's conditions are not met:\n- " .. (reason or "")) + else + editPanel.conditionsFailLoadReasonText:SetText("") + end + end + end end - highlightTexture:Show() end, ---run when the mouse leaves a scroll line + ---@param self df_keybindscrollline OnLeaveScrollLine = function(self) - local highlightTexture = self.highlightTexture - if (not highlightTexture) then - highlightTexture = self:GetParent().highlightTexture + if (self.bIsSeparator) then + return + end + + if (not self.keybindScrollLine) then + --when the mouse enters a child frame, the self is the child frame, not the scroll line + self = self:GetParent() ---@diagnostic disable-line getting the parent from df_keybindscrollline would result in type frame making invalid convertion + ---@cast self df_keybindscrollline + end + + self.highlightTexture:Hide() + + --if the keybind is a macro, a preview might be showing in the edit panel's lua edit box, hide it + local keyBindFrame = getMainFrame(self) + local bIsEditingKeybind = keyBindFrame:IsEditingKeybindSettings() + + if (not bIsEditingKeybind) then + local editPanel = keyBindFrame:GetEditPanel() + editPanel.editMacroEditBox:SetText("") end - highlightTexture:Hide() end, ---@param keybindScroll frame ---@param index number CreateKeybindScrollLine = function(keybindScroll, index) --~create local keyBindFrame = getMainFrame(keybindScroll) + + ---@type df_keybindscrollline local line = CreateFrame("frame", "$parentLine" .. index, keybindScroll) line:SetSize(keyBindFrame.options.width - 10, keyBindFrame.options.line_height) line:SetPoint("topleft", keyBindFrame, "topleft", 1, -22 - (index-1) * keyBindFrame.options.line_height) line:EnableMouse(true) + line.keybindScrollLine = true --detailsFramework:ApplyStandardBackdrop(line, index % 2 == 0) --line:SetBackdropBorderColor(0, 0, 0, 0) + line.backgroundTexture = line:CreateTexture("$parentBackgroundTexture", "background") + line.backgroundTexture:SetAllPoints() + + if (index % 2 == 0) then + line.backgroundTexture:SetColorTexture(0, 0, 0, 0.1) + else + line.backgroundTexture:SetColorTexture(0, 0, 0, 0) + end + line.highlightTexture = line:CreateTexture(nil, "border") line.highlightTexture:SetAllPoints() line.highlightTexture:SetColorTexture(1, 1, 1, .1) @@ -699,57 +885,45 @@ detailsFramework.KeybindMixin = { local options_slider_template = detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE") local options_button_template = detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE") + line.separatorTitleText = line:CreateFontString("$parentSeparatorTitleText", "overlay", "GameFontNormal") + line.separatorTitleText:SetPoint("center", line, "center", 0, 0) + line.spellIconTexture = line:CreateTexture("$parentIcon", "overlay") line.spellIconTexture:SetSize(keyBindFrame.options.line_height - 2, keyBindFrame.options.line_height - 2) - line.spellNameFontString = line:CreateFontString("$parentName", "overlay", "GameFontNormal") - detailsFramework:SetFontColor(line.spellNameFontString, "BLIZZ_OPTIONS_COLOR") - detailsFramework:SetFontSize(line.spellNameFontString, 12) + line.actionNameFontString = line:CreateFontString("$parentName", "overlay", "GameFontNormal") + detailsFramework:SetFontColor(line.actionNameFontString, "BLIZZ_OPTIONS_COLOR") + detailsFramework:SetFontSize(line.actionNameFontString, 12) - line.setKeybindButton = detailsFramework:CreateButton(line, function()end, headerTable[3].width, keyBindFrame.options.line_height-2, "", nil, nil, nil, "SetNewKeybindButton", "$parentSetNewKeybindButton", 0, DARK_BUTTON_TEMPLATE_, options_text_template) - detailsFramework:AddRoundedCornersToFrame(line.setKeybindButton, roundedCornerPreset) + ---@type df_button + line.setKeybindButton = detailsFramework:CreateButton(line, function()end, headerTable[3].width, keyBindFrame.options.line_height-6, "", nil, nil, nil, "SetNewKeybindButton", "$parentSetNewKeybindButton", 0, nil, options_text_template) line.setKeybindButton.textcolor = "white" line.setKeybindButton.textsize = 10 line.setKeybindButton:SetHook("OnEnter", keyBindFrame.OnEnterScrollLine) line.setKeybindButton:SetHook("OnLeave", keyBindFrame.OnLeaveScrollLine) - --line.ActionDrop = detailsFramework:CreateDropDown(line, keyBindFrame.fill_action_dropdown, 0, 120, 20, "ActionDropdown", "$parentActionDropdown", options_dropdown_template) - --line.ActionText = detailsFramework:CreateTextEntry(line, function()end, 660, 20, "TextBox", "$parentActionText", nil, options_dropdown_template) + detailsFramework:AddRoundedCornersToFrame(line.setKeybindButton, roundedCornerPreset) - line.clearKeybindButton = detailsFramework:CreateButton(line, keyBindFrame.ClearKeybind, 16, keyBindFrame.options.line_height-2, "", nil, nil, nil, "DeleteKeybindButton", "$parentDeleteKeybindButton", 2, DARK_BUTTON_TEMPLATE_, options_text_template) + ---@type df_button + line.clearKeybindButton = detailsFramework:CreateButton(line, keyBindFrame.ClearKeybind, 16, keyBindFrame.options.line_height-2, "", nil, nil, nil, "DeleteKeybindButton", "$parentDeleteKeybindButton", 2, nil, options_text_template) line.clearKeybindButton:SetBackdropBorderColor(0, 0, 0, 0) - line.clearKeybindButton:SetIcon([[Interface\Buttons\UI-StopButton]], nil, nil, nil, nil, nil, nil, 4) - line.clearKeybindButton.tooltip = "erase this keybind" + line.clearKeybindButton:SetIcon([[Interface\COMMON\CommonIcons]], nil, nil, nil, {0.1264, 0.2514, 0.5048, 0.7548}, nil, nil, 4) - --editbox - --[=[ - line.ActionText:SetJustifyH("left") - line.ActionText:SetHook("OnEscapePressed", keyBindFrame.set_action_on_espace_press) - line.ActionText:SetHook("OnEditFocusGained", function() - local playerSpells = {} - local tab, tabTex, offset, numSpells = GetSpellTabInfo(2) - for i = 1, numSpells do - local index = offset + i - local spellType, actionId = GetSpellBookItemInfo(index, "player") - if (spellType == "SPELL") then - local spellName = GetSpellInfo(actionId) - tinsert(playerSpells, spellName) - end - end - line.ActionText.WordList = playerSpells - end) + ---@type df_button + line.editKeybindSettingsButton = detailsFramework:CreateButton(line, keyBindFrame.StartEditingKeybindSettings, 16, keyBindFrame.options.line_height-2, "", nil, nil, nil, "EditKeybindButton", "$parentEditKeybindButton", 2, nil, options_text_template) + line.editKeybindSettingsButton:SetBackdropBorderColor(0, 0, 0, 0) + line.editKeybindSettingsButton:SetIcon([[Interface\BUTTONS\UI-GuildButton-PublicNote-Disabled]]) - line.ActionText:SetAsAutoComplete("WordList") - --]=] line:AddFrameToHeaderAlignment(line.spellIconTexture) - line:AddFrameToHeaderAlignment(line.spellNameFontString) + line:AddFrameToHeaderAlignment(line.actionNameFontString) line:AddFrameToHeaderAlignment(line.setKeybindButton) - --line:AddFrameToHeaderAlignment(line.ActionDrop) - --line:AddFrameToHeaderAlignment(line.ActionText) line:AddFrameToHeaderAlignment(line.clearKeybindButton) + line:AddFrameToHeaderAlignment(line.editKeybindSettingsButton) line:AlignWithHeader(keyBindFrame.Header, "left") + line.SetAsSeparator = setAsSeparator + return line end, @@ -766,6 +940,41 @@ detailsFramework.KeybindMixin = { self.Header = DetailsFramework:CreateHeader(self, headerTable, headerOptions) self.Header:SetPoint("topleft", self, "topleft", 0, 0) + local onClickCreateMacroButton = function() --~macro + local newMacroName = "New @Macro (" .. math.random(10000, 99999) .. ")" + local actionIdentifier = "macro-" .. newMacroName + + local keybindTable = createNewKeybindTable(newMacroName, "", "/say Hi", actionIdentifier, 136377) + local pressedKeybind = "" + + if (self.options.can_modify_keybind_data) then + --if the options for this frame allows it to change the keybind in the addon savedVariables, then do it + local bKeybindJustCreated = true + self:SaveKeybindToKeybindData(keybindTable, pressedKeybind, bKeybindJustCreated) + end + + self:CallKeybindChangeCallback("modified", keybindTable, pressedKeybind) + + local keybindScroll = self:GetKeybindScroll() + keybindScroll:UpdateScroll() + + --start editing this keybindTable + self:StartEditingKeybindSettings("LeftButton", actionIdentifier, keybindTable) + + --get the keybind editor frame + ---@type df_editkeybindframe + local keybindEditor = self:GetEditPanel() + + local macroEditBox = keybindEditor.editMacroEditBox + macroEditBox:SetText(keybindTable.macro) + macroEditBox:SetFocus() + end + + local createMacroButton = detailsFramework:CreateButton(self.Header, onClickCreateMacroButton, 100, 20, "Create Macro Keybind", nil, nil, nil, "CreateMacroButton", "$parentCreateMacroButton", 0, DARK_BUTTON_TEMPLATE, detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) + createMacroButton:SetPoint("left", self.Header, "left", 0, 0) + createMacroButton:SetFrameLevel(self.Header:GetFrameLevel()+10) + createMacroButton:SetIcon(136377) + local keybindScroll = detailsFramework:CreateScrollBox(self, "$parentScrollBox", detailsFramework.KeybindMixin.RefreshKeybindScroll, {}, scroll_width, scroll_height, scroll_lines, scroll_line_height) ---@cast keybindScroll df_keybindscroll @@ -781,13 +990,106 @@ detailsFramework.KeybindMixin = { keybindScroll:CreateLine(self.CreateKeybindScrollLine) end + --scroll data constructor function keybindScroll.UpdateScroll() --~update --keybind data from saved variables + ---@type df_keybind[] local data = self:GetKeybindData() + --pre build keybind data to be used by the scroll data constructor + ---@type table + local keybindDataParsed = {} + + ---@type df_keybind[] + local allKeybindMacros = {} + + --iterage amoung keybinds already set by the user + --and fill the tables 'keybindDataParsed' where the key is actionId and the value is the keybind data + --also fill the table 'allKeybindMacros' with all macros, this is an array with keybind data + for i = 1, #data do + ---@type df_keybind + local keybindData = data[i] + + local actionId = keybindData.action --the actionId can be "macro" for macros + local keybind = keybindData.keybind --the keybind to active the action + local macro = keybindData.macro --macro here is the macro text + local name = keybindData.name --for macros it shows the macro name where the spellName is for instance + local icon = keybindData.icon --for macros the user can set an icon + local conditions = keybindData.conditions --allows the user to set conditions for the keybind to be active + + local bIsSpell = actionId and type(actionId) == "number" + if (bIsSpell) then + local spellId = actionId + keybindDataParsed[spellId] = keybindData + + elseif (defaultMouseKeybindsKV[actionId]) then + keybindDataParsed[actionId] = keybindData --"target" "focus" "togglemenu" + + end + + if (type(actionId) == "string" and self:IsKeybindActionMacro(actionId)) then + table.insert(allKeybindMacros, keybindData) + end + end + ---@type keybind_scroll_data[] local scrollData = {} + ---@type keybind_scroll_data[] store spells that are not available, they are added after the spells available + local spellsNotAvailable = {} + + ---@type keybind_scroll_data[] store macros that are not available, they are added after the spells available + local macrosNotAvailable = {} + + table.insert(scrollData, {"@separator", "Regualar Actions", "", "", false, -1}) + + if (self.options.show_unitcontrols) then + for i, mouseActionKeyInfo in ipairs(defaultMouseKeybinds) do + local mouseActionId = mouseActionKeyInfo.action + local mouseDefaultKeybind = mouseActionKeyInfo.keybind + local mouseIcon = mouseActionKeyInfo.icon + local mouseActionName = mouseActionKeyInfo.name + + local keybindData = keybindDataParsed[mouseActionId] + local actionIdentifier = "system-" .. mouseActionId + + local thisScrollData = {keybindData and keybindData.name or mouseActionName, keybindData and keybindData.icon or mouseIcon, mouseActionId, keybindData or false, true, 0, actionIdentifier} + table.insert(scrollData, 1+i, thisScrollData) + end + end + + table.insert(scrollData, {"@separator", "Macros", "", "", false, 1}) + + if (self.options.show_macros) then + --sort the table alphabetically + table.sort(allKeybindMacros, function(t1, t2) return t1.name < t2.name end) + + for i, keybindData in ipairs(allKeybindMacros) do + local macroName = keybindData.name + local macroIcon = keybindData.icon + local macroText = keybindData.macro + local actionId = keybindData.action + local conditions = keybindData.conditions + + local bCanLoad = detailsFramework:PassLoadFilters(conditions) + local sortScore = 2 + + local actionIdentifier = actionId + + ---@type keybind_scroll_data + local thisScrollData = {macroName, macroIcon, actionId, keybindData, bCanLoad, sortScore, actionIdentifier} + if (bCanLoad) then + table.insert(scrollData, thisScrollData) + else + table.insert(macrosNotAvailable, thisScrollData) + end + end + end + + table.insert(scrollData, {"@separator", "Spells", "", "", false, 3}) + + local indexToAddNotAvailableMacros = #scrollData + 1 + if (self.options.show_spells) then --the a list of all spells local allPlayerSpells = detailsFramework:GetAvailableSpells() @@ -795,24 +1097,46 @@ detailsFramework.KeybindMixin = { for spellId, bIsAvailable in pairs(allPlayerSpells) do local spellName, _, spellIcon = GetSpellInfo(spellId) if (spellName) then - local keybind = data[spellId] or "" - local sortScore = (bIsAvailable and 0 or 200) + string.byte(spellName) -- + (keybind ~= "" and 100 or 0) + ---@type df_keybind|nil + local keybindData = keybindDataParsed[spellId] --could be nil if doesn't exists + + --show spells with keybinds at the top of the list, then show spells that are available, then show spells that are not available + --always sub sorting by the spell name + local sortScore = getSpellSortOrder(keybindData, spellName, bIsAvailable) local actionId = spellId - scrollData[#scrollData+1] = {spellName, spellIcon, actionId, keybind, bIsAvailable, sortScore} + + local actionIdentifier = "spell-" .. actionId + + ---@type keybind_scroll_data + local thisScrollData = {keybindData and keybindData.name or spellName, keybindData and keybindData.icon or spellIcon, actionId, keybindData or false, bIsAvailable, sortScore, actionIdentifier} + + if (not bIsAvailable) then + spellsNotAvailable[#spellsNotAvailable+1] = thisScrollData + else + scrollData[#scrollData+1] = thisScrollData + end end end table.sort(scrollData, function(a, b) return a[6] < b[6] end) + table.sort(spellsNotAvailable, function(a, b) return a[6] < b[6] end) end - if (self.options.show_unitcontrols) then - for i, actionKeyInfo in ipairs(unitControlKeybinds) do - local actionName = actionKeyInfo.localizedName - local defaultKeybind = actionKeyInfo.keybind - local keybind = data[actionName] or defaultKeybind - local icon = actionKeyInfo.icon - local actionId = actionKeyInfo.name - table.insert(scrollData, 1, {actionName, icon, actionId, keybind, defaultKeybind, 0}) + if (#macrosNotAvailable > 0) then + table.insert(scrollData, {"@separator", "Macros Not Available", "", "", false, 1}) + + for i = 1, #macrosNotAvailable do + local thisScrollData = macrosNotAvailable[i] + table.insert(scrollData, thisScrollData) + end + end + + if (#spellsNotAvailable > 0) then + table.insert(scrollData, {"@separator", "Spells Not Available", "", "", false, 3}) + + for i = 1, #spellsNotAvailable do + local thisScrollData = spellsNotAvailable[i] + table.insert(scrollData, thisScrollData) end end @@ -823,7 +1147,7 @@ detailsFramework.KeybindMixin = { ---return the keybind data ---@param self df_keybindframe - ---@return df_keybinddata + ---@return df_keybind[] GetKeybindData = function(self) return self.data end, @@ -831,7 +1155,7 @@ detailsFramework.KeybindMixin = { ---set the keybind data from a profile ---data consists in a table where the actionId (any) is the key and the value is the keybind (string) ---@param self df_keybindframe - ---@param newData df_keybinddata + ---@param newData df_keybind[] SetKeybindData = function(self, newData) self.data = newData local keybindScroll = self:GetKeybindScroll() @@ -853,12 +1177,311 @@ detailsFramework.KeybindMixin = { return self.callback end, - OnKeybindChanged = function(self, actionId, keybind) + ---@param self df_keybindframe + ---@param type string "modified", "removed", "conditions", "name" + ---@param keybindTable df_keybind? + ---@param keybindPressed string? + ---@param removedIndex number? + ---@param macroText string? + CallKeybindChangeCallback = function(self, type, keybindTable, keybindPressed, removedIndex, macroText) local callbackFunc = self:GetKeybindCallback() if (callbackFunc) then - detailsFramework:Dispatch(callbackFunc, actionId, keybind) + detailsFramework:Dispatch(callbackFunc, self, type, keybindTable, keybindPressed, removedIndex, macroText) end end, + + ---@param self df_keybindframe + ---@param actionId any + IsKeybindActionMacro = function(self, actionId) + if (type(actionId) == "string") then + return actionId:match("^macro%-") + end + end, + + ---on press enter on the edit frame name editbox + ---@param self df_keybindframe + ---@param newName string + OnKeybindNameChange = function(self, newName) + local editFrame = self:GetEditPanel() + local keybindTable = editFrame.keybindTable + + local actionId = keybindTable.action + ---@cast actionId string + + keybindTable.name = newName + + if (self:IsKeybindActionMacro(actionId)) then + keybindTable.action = "macro-" .. newName + end + + self:CallKeybindChangeCallback("name", keybindTable) + + local keybindScroll = self:GetKeybindScroll() + keybindScroll:UpdateScroll() + end, + + ---@param self df_keybindframe + ---@param macroText string + OnKeybindMacroChange = function(self, macroText) + ---@type df_keybindframe + local keyBindFrame = getMainFrame(self) + + local editFrame = keyBindFrame:GetEditPanel() + local keybindTable = editFrame.keybindTable + + if (keyBindFrame.options.can_modify_keybind_data) then + keybindTable.macro = macroText + end + + keyBindFrame:CallKeybindChangeCallback("macro", keybindTable, nil, nil, macroText) + end, + + OnKeybindIconChange = function(self, texture) + local editFrame = self:GetEditPanel() + local keybindTable = editFrame.keybindTable + keybindTable.icon = texture + self:CallKeybindChangeCallback("icon", keybindTable) + end, + + ---return true if the user is editing a keybind + ---@param self df_keybindframe + ---@return boolean bIsEditing + ---@return string actionIdentifier + ---@return df_keybind keybindTable + IsEditingKeybindSettings = function(self) + local editFrame = self:GetEditPanel() + return editFrame.bIsEditing, editFrame.actionIdentifier, editFrame.keybindTable + end, + + ---start editing the keybind settings + ---@param self frame + ---@param button string + ---@param actionIdentifier string + ---@param keybindTable df_keybind + StartEditingKeybindSettings = function(self, button, actionIdentifier, keybindTable) + ---@type df_keybindframe + local keyBindFrame = getMainFrame(self) + + local bIsListening = keyBindFrame:GetListeningState() + if (bIsListening) then + return + end + + local editFrame = keyBindFrame:GetEditPanel() + editFrame:Enable() + + editFrame.nameEditBox:SetText(keybindTable.name) + editFrame.iconPickerButton:SetIcon(keybindTable.icon) + + local actionId = keybindTable.action + ---@cast actionId string + if (keyBindFrame:IsKeybindActionMacro(actionId)) then + editFrame.editMacroEditBox:SetText(keybindTable.macro) + editFrame.deleteMacroButton:Enable() + else + editFrame.editMacroEditBox:Disable() + editFrame.deleteMacroButton:Disable() + end + + editFrame.actionIdentifier = actionIdentifier + editFrame.keybindTable = keybindTable + editFrame.bIsEditing = true + end, + + ---disable and clear all entries in the edit frame + ---@param self df_keybindframe + StopEditingKeybindSettings = function(self) + local editFrame = self:GetEditPanel() + editFrame.bIsEditing = false + editFrame.actionIdentifier = nil + editFrame.keybindTable = nil + editFrame:Disable() + end, + + ---return the editing keybind frame + ---@param self df_keybindframe + ---@return df_editkeybindframe + GetEditPanel = function(self) + return self.editKeybindFrame + end, + + ---@param self df_keybindframe + CreateEditPanel = function(self) --~edit + local options_text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE") + local options_dropdown_template = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE") + local options_switch_template = detailsFramework:GetTemplate("switch", "OPTIONS_CHECKBOX_TEMPLATE") + local options_slider_template = detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE") + local options_button_template = detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE") + + ---@type df_editkeybindframe + local editFrame = CreateFrame("frame", "$parentEditPanel", self, "BackdropTemplate") + editFrame:SetSize(self.options.edit_width, self.options.edit_height) + editFrame:SetPoint("topleft", self, "topright", 28, 0) --give space for the scrollbar + self.editKeybindFrame = editFrame + + --name + local nameText = editFrame:CreateFontString("$parentNameText", "overlay", "GameFontNormal") + nameText:SetPoint("topleft", editFrame, "topleft", 10, -10) + nameText:SetText("Name:") + detailsFramework:SetFontColor(nameText, "BLIZZ_OPTIONS_COLOR") + + local nameEditBoxCallback = function(param1, param2, text) + --print("name change", param1, param2, text) + --self:OnKeybindNameChange(text) + end + local nameEditBox = detailsFramework:CreateTextEntry(editFrame, nameEditBoxCallback, 200, 20, "nameEditBox", "$parentNameEditBox", nil, options_dropdown_template) + nameEditBox:SetPoint("topleft", nameText, "bottomleft", 0, -5) + nameEditBox:SetBackdropColor(.1, .1, .1, .834) + nameEditBox:SetJustifyH("left") + nameEditBox:SetTextInsets(5, 3, 0, 0) + + --icon + local iconText = editFrame:CreateFontString("$parentIconText", "overlay", "GameFontNormal") + iconText:SetPoint("topleft", nameEditBox.widget, "bottomleft", 0, -10) + iconText:SetText("Icon:") + detailsFramework:SetFontColor(iconText, "BLIZZ_OPTIONS_COLOR") + + local iconPickerButtonCallback = function(texture) + editFrame.iconPickerButton:SetIcon(texture) + --self:OnKeybindIconChange(texture) + end + + local iconPickerButton = detailsFramework:CreateButton(editFrame, function() detailsFramework:IconPick(iconPickerButtonCallback, true) end, 20, 20, "", nil, nil, nil, "iconPickerButton", "$parentIconPickerButton", 0, DARK_BUTTON_TEMPLATE, detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) + iconPickerButton:SetPoint("topleft", iconText, "bottomleft", 0, -5) + iconPickerButton:SetIcon([[]], nil, nil, nil, {0.1264, 0.2514, 0.5048, 0.7548}, nil, nil, 4) + iconPickerButton.tooltip = "pick an icon" + + --macro + local editMacroText = editFrame:CreateFontString("$parentEditMacroText", "overlay", "GameFontNormal") + editMacroText:SetPoint("topleft", iconPickerButton.widget, "bottomleft", 0, -10) + editMacroText:SetText("Macro:") + detailsFramework:SetFontColor(editMacroText, "BLIZZ_OPTIONS_COLOR") + + ---@type df_luaeditor + local editMacroEditBox = detailsFramework:NewSpecialLuaEditorEntry(editFrame, self.options.edit_width-35, 200, "editMacroEditBox", "$parentEditMacroEditBox", true) + editMacroEditBox:SetBackdrop ({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true}) + editMacroEditBox:SetBackdropBorderColor(0, 0, 0, 1) + editMacroEditBox:SetBackdropColor(.1, .1, .1, .5) + detailsFramework:ReskinSlider(editMacroEditBox.scroll) + editMacroEditBox:SetPoint("topleft", editMacroText, "bottomleft", 0, -5) + + editMacroEditBox["Center"]:SetColorTexture(.1, .1, .1, .834) + + local saveButtonCallback = function() + local bIsEditing, actionIdentifier, keybindTable = self:IsEditingKeybindSettings() + if (bIsEditing and keybindTable) then + local keybindName = nameEditBox:GetText() + local iconTexture = editFrame.iconPickerButton.icon + local keybindTexture = iconTexture:GetTexture() + local keybindMacroText = editMacroEditBox:GetText() + + --check if the macro has default name and icon + if (keybindName:find("@Macro") and iconTexture:GetTexture() == 136377) then + for macro in keybindMacroText:gmatch("([^%s]+)") do + local spellName, _, spellIcon = GetSpellInfo(macro) + if (spellName) then + keybindName = spellName + keybindTexture = spellIcon + end + end + end + + self:OnKeybindNameChange(keybindName) + self:OnKeybindIconChange(keybindTexture) + + local actionId = keybindTable.action + ---@cast actionId string + + if (self:IsKeybindActionMacro(actionId)) then + self:OnKeybindMacroChange(keybindMacroText) + end + end + + self:StopEditingKeybindSettings() + + local keybindScroll = self:GetKeybindScroll() + keybindScroll:UpdateScroll() + end + + --save button + local saveButton = detailsFramework:CreateButton(editFrame, saveButtonCallback, 120, 20, "Save", nil, nil, nil, "saveButton", "$parentSaveButton", 0, DARK_BUTTON_TEMPLATE, detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) + saveButton:SetPoint("topleft", editMacroEditBox, "bottomleft", 0, -10) + saveButton:SetIcon([[Interface\BUTTONS\UI-CheckBox-Check]]) + + local cancelButtonCallback = function() + self:StopEditingKeybindSettings() + end + + --cancel button + local cancelButton = detailsFramework:CreateButton(editFrame, cancelButtonCallback, 120, 20, "Cancel", nil, nil, nil, "cancelButton", "$parentCancelButton", 0, DARK_BUTTON_TEMPLATE, detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) + cancelButton:SetPoint("left", saveButton, "right", 10, 0) + cancelButton:SetIcon([[Interface\BUTTONS\UI-GROUPLOOT-PASS-DOWN]]) + + --conditions + local conditionsText = editFrame:CreateFontString("$parentConditionsText", "overlay", "GameFontNormal") + conditionsText:SetPoint("topleft", saveButton.widget, "bottomleft", 0, -40) + conditionsText:SetText("Can Load Keybind?") + detailsFramework:SetFontColor(conditionsText, "BLIZZ_OPTIONS_COLOR") + + local onLoadConditionsChange = function() + --no parameters is passed as the modifications are done directly on the keybindTable.conditions + --trigger a callback to inform the addon about the change + self:CallKeybindChangeCallback("conditions", editFrame.keybindTable) + end + + local openConditionsPanel = function() + local conditionsSettings = editFrame.keybindTable.conditions + detailsFramework:OpenLoadConditionsPanel(conditionsSettings, onLoadConditionsChange, {title = "Keybind Load Conditions", name = editFrame.keybindTable.name}) + end + + local conditionsButton = detailsFramework:CreateButton(editFrame, openConditionsPanel, 160, 20, "Edit Load Conditions", nil, nil, [[]], "conditionsButton", "$parentConditionsButton", 0, DARK_BUTTON_TEMPLATE, detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) + conditionsButton:SetPoint("topleft", conditionsText, "bottomleft", 0, -5) + + local conditionsFailLoadReasonText = editFrame:CreateFontString("$parentConditionsFailLoadText", "overlay", "GameFontNormal") + conditionsFailLoadReasonText:SetPoint("topleft", conditionsButton.widget, "bottomleft", 0, -20) + conditionsFailLoadReasonText:SetText("") + conditionsFailLoadReasonText:SetJustifyH("left") + detailsFramework:SetFontColor(conditionsFailLoadReasonText, "firebrick") + editFrame.conditionsFailLoadReasonText = conditionsFailLoadReasonText + + --create a button to delete a macro keybind + local deleteMacroText = editFrame:CreateFontString("$parentDeleteMacroText", "overlay", "GameFontNormal") + deleteMacroText:SetPoint("topleft", saveButton.widget, "bottomleft", 180, -40) + deleteMacroText:SetText("Delete Macro") + detailsFramework:SetFontColor(deleteMacroText, "BLIZZ_OPTIONS_COLOR") + + local onClickDeleteMacroButton = function() + self:DeleteMacro() + end + + local deleteMacroButton = detailsFramework:CreateButton(editFrame, onClickDeleteMacroButton, 160, 20, "Delete This Macro", nil, nil, [[]], "deleteMacroButton", "$parentDeleteMacroButton", 0, DARK_BUTTON_TEMPLATE, detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")) + deleteMacroButton:SetPoint("topleft", deleteMacroText, "bottomleft", 0, -5) + + --methods + function editFrame:Disable() + nameEditBox:SetText("") + nameEditBox:Disable() + editMacroEditBox:SetText("") + editMacroEditBox:Disable() + iconPickerButton:Disable() + conditionsButton:Disable() + deleteMacroButton:Disable() + saveButton:Disable() + cancelButton:Disable() + end + + function editFrame:Enable() + nameEditBox:Enable() + iconPickerButton:Enable() + conditionsButton:Enable() + deleteMacroButton:Enable() + editMacroEditBox:Enable() + saveButton:Enable() + cancelButton:Enable() + end + + editFrame:Disable() + end, } ---@param parent frame @@ -884,6 +1507,10 @@ function detailsFramework:CreateKeybindFrame(parent, name, options, setKeybindCa keyBindFrame.options.scroll_width = keyBindFrame.options.width - 10 end + if (keyBindFrame.options.edit_height == 0) then + keyBindFrame.options.edit_height = keyBindFrame.options.height + end + keyBindFrame:SetSize(keyBindFrame.options.width, keyBindFrame.options.height) keyBindFrame:SetScript("OnHide", function() @@ -892,10 +1519,24 @@ function detailsFramework:CreateKeybindFrame(parent, name, options, setKeybindCa local keybindListener = keyBindFrame:GetKeybindListener() keybindListener:SetScript("OnKeyDown", nil) end + + local bIsEditingKeybind = keyBindFrame:IsEditingKeybindSettings() + if (bIsEditingKeybind) then + keyBindFrame:StopEditingKeybindSettings() + end + + keyBindFrame:SetClearButtonsEnabled(true) + keyBindFrame:SetEditButtonsEnabled(true) + end) + + keyBindFrame:SetScript("OnShow", function() + local keybindScroll = keyBindFrame:GetKeybindScroll() + keybindScroll:UpdateScroll() end) keyBindFrame:CreateKeybindScroll() keyBindFrame:CreateKeybindListener() + keyBindFrame:CreateEditPanel() keyBindFrame:SetKeybindData(keybindData or {}) diff --git a/Libs/DF/load.xml b/Libs/DF/load.xml index a8e9c477..b01f71ee 100644 --- a/Libs/DF/load.xml +++ b/Libs/DF/load.xml @@ -23,7 +23,7 @@