map markers, search, export\import like retail, some bug fixes (#21)
* fix middle button on click map * fix pvp buttons * map markers search dev tools and fixes * fixes and loc * loc * fix * typo * typo * fix
This commit is contained in:
+3
-2
@@ -58,6 +58,7 @@ E.myLocalizedClass, E.myclass = UnitClass("player") -- On Ascension, this is al
|
||||
E.myLocalizedRace, E.myrace = UnitRace("player")
|
||||
E.myname = UnitName("player")
|
||||
E.myrealm = GetRealmName()
|
||||
E.mynameRealm = format('%s - %s', E.myname, E.myrealm) -- contains spaces/dashes in realm (for profile keys)
|
||||
E.version = GetAddOnMetadata("ElvUI", "Version")
|
||||
E.wowpatch, E.wowbuild = GetBuildInfo()
|
||||
E.wowbuild = tonumber(E.wowbuild)
|
||||
@@ -802,8 +803,8 @@ function E:UpdateAll(ignoreInstall)
|
||||
Chat:UpdateAnchors()
|
||||
end
|
||||
|
||||
DataBars:EnableDisable_ExperienceBar()
|
||||
DataBars:EnableDisable_ReputationBar()
|
||||
DataBars:ExperienceBar_Toggle()
|
||||
DataBars:ReputationBar_Toggle()
|
||||
DataBars:UpdateDataBarDimensions()
|
||||
|
||||
DataTexts:LoadDataTexts()
|
||||
|
||||
+286
-267
@@ -1,104 +1,195 @@
|
||||
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
|
||||
local D = E:GetModule("Distributor")
|
||||
local LibCompress = E.Libs.Compress
|
||||
local LibBase64 = E.Libs.Base64
|
||||
local E, L, V, P, G = unpack(select(2,...))
|
||||
local D = E:GetModule('Distributor')
|
||||
local NP = E:GetModule('NamePlates')
|
||||
local LibDeflate = E.Libs.Deflate
|
||||
|
||||
local _G = _G
|
||||
local tonumber, type, gsub, pairs, pcall, loadstring = tonumber, type, gsub, pairs, pcall, loadstring
|
||||
local len, format, split, strmatch = strlen, format, strsplit, strmatch
|
||||
|
||||
--Lua functions
|
||||
local loadstring = loadstring
|
||||
local pcall = pcall
|
||||
local setfenv = setfenv
|
||||
local tonumber = tonumber
|
||||
local type = type
|
||||
local format, gsub, len, split, sub = string.format, string.gsub, string.len, string.split, string.sub
|
||||
--WoW API / Variables
|
||||
local CreateFrame = CreateFrame
|
||||
local GetNumRaidMembers, UnitInRaid = GetNumRaidMembers, UnitInRaid
|
||||
local GetNumPartyMembers, UnitInParty = GetNumPartyMembers, UnitInParty
|
||||
local IsInRaid, UnitInRaid = IsInRaid, UnitInRaid
|
||||
local IsInGroup, UnitInParty = IsInGroup, UnitInParty
|
||||
-- local LE_PARTY_CATEGORY_HOME = LE_PARTY_CATEGORY_HOME
|
||||
-- local LE_PARTY_CATEGORY_INSTANCE = LE_PARTY_CATEGORY_INSTANCE
|
||||
local ACCEPT, CANCEL, YES, NO = ACCEPT, CANCEL, YES, NO
|
||||
-- GLOBALS: ElvDB, ElvPrivateDB
|
||||
|
||||
----------------------------------
|
||||
-- CONSTANTS
|
||||
----------------------------------
|
||||
local EXPORT_PREFIX = '!E1!' -- also in Options StyleFilters
|
||||
local REQUEST_PREFIX = 'ELVUI_REQUEST'
|
||||
local REPLY_PREFIX = 'ELVUI_REPLY'
|
||||
local TRANSFER_PREFIX = 'ELVUI_TRANSFER'
|
||||
local TRANSFER_COMPLETE_PREFIX = 'ELVUI_COMPLETE'
|
||||
|
||||
local REQUEST_PREFIX = "ELVUI_REQUEST"
|
||||
local REPLY_PREFIX = "ELVUI_REPLY"
|
||||
local TRANSFER_PREFIX = "ELVUI_TRANSFER"
|
||||
local TRANSFER_COMPLETE_PREFIX = "ELVUI_COMPLETE"
|
||||
|
||||
local ACECOMMPREFIXES = {
|
||||
[TRANSFER_PREFIX.."\001"] = true,
|
||||
[TRANSFER_PREFIX.."\002"] = true,
|
||||
[TRANSFER_PREFIX.."\003"] = true,
|
||||
}
|
||||
-- Set compression
|
||||
LibDeflate.compressLevel = { level = 5 }
|
||||
|
||||
-- The active downloads
|
||||
local Downloads = {}
|
||||
local Uploads = {}
|
||||
|
||||
--Keys that should not be exported
|
||||
D.blacklistedKeys = {
|
||||
profile = {
|
||||
gridSize = true,
|
||||
general = {
|
||||
cropIcon = true,
|
||||
numberPrefixStyle = true
|
||||
},
|
||||
chat = {
|
||||
hideVoiceButtons = true
|
||||
},
|
||||
bags = {
|
||||
shownBags = true
|
||||
}
|
||||
},
|
||||
private = {},
|
||||
global = {
|
||||
profileCopy = true,
|
||||
general = {
|
||||
AceGUI = true,
|
||||
UIScale = true,
|
||||
locale = true,
|
||||
version = true,
|
||||
eyefinity = true,
|
||||
ultrawide = true,
|
||||
disableTutorialButtons = true,
|
||||
allowDistributor = true
|
||||
},
|
||||
chat = {
|
||||
classColorMentionExcludedNames = true
|
||||
},
|
||||
datatexts = {
|
||||
newPanelInfo = true,
|
||||
settings = {
|
||||
Currencies = {
|
||||
tooltipData = true
|
||||
}
|
||||
}
|
||||
},
|
||||
nameplates = {
|
||||
filters = true
|
||||
},
|
||||
unitframe = {
|
||||
aurafilters = true,
|
||||
aurawatch = true,
|
||||
newCustomText = true,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
--Keys that auto or user generated tables.
|
||||
D.GeneratedKeys = {
|
||||
profile = {
|
||||
convertPages = true,
|
||||
movers = true,
|
||||
actionbar = {},
|
||||
nameplates = { -- this is supposed to have an 's' because yeah, oh well
|
||||
filters = true
|
||||
},
|
||||
datatexts = {
|
||||
panels = true,
|
||||
},
|
||||
unitframe = {
|
||||
units = {} -- required for the scope below for customTexts
|
||||
}
|
||||
},
|
||||
private = {
|
||||
theme = true,
|
||||
install_complete = true
|
||||
},
|
||||
global = {
|
||||
datatexts = {
|
||||
customPanels = true,
|
||||
customCurrencies = true
|
||||
},
|
||||
unitframe = {
|
||||
AuraBarColors = true,
|
||||
aurafilters = true,
|
||||
aurawatch = true
|
||||
},
|
||||
nameplates = {
|
||||
filters = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
local units = D.GeneratedKeys.profile.unitframe.units
|
||||
for unit in pairs(P.unitframe.units) do
|
||||
units[unit] = {customTexts = true}
|
||||
end
|
||||
|
||||
for i = 1, 10 do
|
||||
D.GeneratedKeys.profile.actionbar['bar'..i] = { paging = true }
|
||||
end
|
||||
end
|
||||
|
||||
function D:Initialize()
|
||||
self.Initialized = true
|
||||
self:RegisterComm(REQUEST_PREFIX)
|
||||
self:RegisterEvent("CHAT_MSG_ADDON")
|
||||
|
||||
self.statusBar = CreateFrame("StatusBar", "ElvUI_Download", E.UIParent)
|
||||
E:RegisterStatusBar(self.statusBar)
|
||||
self.statusBar:CreateBackdrop("Default")
|
||||
D:UpdateSettings()
|
||||
|
||||
self.statusBar = CreateFrame('StatusBar', 'ElvUI_Download', E.UIParent)
|
||||
self.statusBar:CreateBackdrop()
|
||||
self.statusBar:SetStatusBarTexture(E.media.normTex)
|
||||
self.statusBar:SetStatusBarColor(0.95, 0.15, 0.15)
|
||||
self.statusBar:Size(250, 18)
|
||||
self.statusBar.text = self.statusBar:CreateFontString(nil, "OVERLAY")
|
||||
self.statusBar.text = self.statusBar:CreateFontString(nil, 'OVERLAY')
|
||||
self.statusBar.text:FontTemplate()
|
||||
self.statusBar.text:Point("CENTER")
|
||||
self.statusBar.text:Point('CENTER')
|
||||
self.statusBar:Hide()
|
||||
E:RegisterStatusBar(self.statusBar)
|
||||
end
|
||||
|
||||
function D:UpdateSettings()
|
||||
if E.global.general.allowDistributor then
|
||||
self:RegisterComm(REQUEST_PREFIX)
|
||||
self:RegisterEvent('CHAT_MSG_ADDON')
|
||||
else
|
||||
self:UnregisterComm(REQUEST_PREFIX)
|
||||
self:UnregisterEvent('CHAT_MSG_ADDON')
|
||||
end
|
||||
end
|
||||
|
||||
-- Used to start uploads
|
||||
function D:Distribute(target, otherServer, isGlobal)
|
||||
local profileKey, data
|
||||
if not isGlobal then
|
||||
if ElvDB.profileKeys then
|
||||
profileKey = ElvDB.profileKeys[E.myname.." - "..E.myrealm]
|
||||
end
|
||||
|
||||
profileKey = ElvDB.profileKeys and ElvDB.profileKeys[E.mynameRealm]
|
||||
data = ElvDB.profiles[profileKey]
|
||||
else
|
||||
profileKey = "global"
|
||||
profileKey = 'global'
|
||||
data = ElvDB.global
|
||||
end
|
||||
|
||||
if not data or not profileKey then return end
|
||||
|
||||
data = E:RemoveTableDuplicates(data, isGlobal and G or P)
|
||||
if not data then return end
|
||||
|
||||
local serialData = self:Serialize(data)
|
||||
local length = len(serialData)
|
||||
local message = format("%s:%d:%s", profileKey, length, target)
|
||||
local message = format('%s:%d:%s', profileKey, length, target)
|
||||
|
||||
Uploads[profileKey] = {
|
||||
serialData = serialData,
|
||||
target = target,
|
||||
}
|
||||
Uploads[profileKey] = {serialData = serialData, target = target}
|
||||
|
||||
if otherServer then
|
||||
local numParty, numRaid = GetNumPartyMembers(), GetNumRaidMembers()
|
||||
if numRaid > 0 and UnitInRaid("target") then
|
||||
self:SendCommMessage(REQUEST_PREFIX, message, "RAID")
|
||||
elseif numParty > 0 and UnitInParty("target") then
|
||||
self:SendCommMessage(REQUEST_PREFIX, message, "PARTY")
|
||||
if IsInRaid() and UnitInRaid('target') then
|
||||
self:SendCommMessage(REQUEST_PREFIX, message, 'RAID')
|
||||
elseif IsInGroup() and UnitInParty('target') then
|
||||
self:SendCommMessage(REQUEST_PREFIX, message, 'PARTY')
|
||||
else
|
||||
E:Print(L["Must be in group with the player if he isn't on the same server as you."])
|
||||
return
|
||||
end
|
||||
else
|
||||
self:SendCommMessage(REQUEST_PREFIX, message, "WHISPER", target)
|
||||
self:SendCommMessage(REQUEST_PREFIX, message, 'WHISPER', target)
|
||||
end
|
||||
|
||||
self:RegisterComm(REPLY_PREFIX)
|
||||
E:StaticPopup_Show("DISTRIBUTOR_WAITING")
|
||||
E:StaticPopup_Show('DISTRIBUTOR_WAITING')
|
||||
end
|
||||
|
||||
function D:CHAT_MSG_ADDON(_, prefix, message, _, sender)
|
||||
if not ACECOMMPREFIXES[prefix] or not Downloads[sender] then return end
|
||||
|
||||
if prefix ~= TRANSFER_PREFIX or not Downloads[sender] then return end
|
||||
local cur = len(message)
|
||||
local max = Downloads[sender].length
|
||||
Downloads[sender].current = Downloads[sender].current + cur
|
||||
@@ -110,29 +201,21 @@ function D:CHAT_MSG_ADDON(_, prefix, message, _, sender)
|
||||
self.statusBar:SetValue(Downloads[sender].current)
|
||||
end
|
||||
|
||||
function D:UpdateSendProgress(sentBytes, totalBytes)
|
||||
self.statusBar:SetValue(sentBytes)
|
||||
|
||||
if sentBytes == totalBytes then
|
||||
E:StaticPopupSpecial_Hide(self.statusBar)
|
||||
end
|
||||
end
|
||||
|
||||
function D:OnCommReceived(prefix, msg, dist, sender)
|
||||
if prefix == REQUEST_PREFIX then
|
||||
local profile, length, sendTo = split(":", msg)
|
||||
local profile, length, sendTo = split(':', msg)
|
||||
|
||||
if dist ~= "WHISPER" and sendTo ~= E.myname then
|
||||
if dist ~= 'WHISPER' and sendTo ~= E.myname then
|
||||
return
|
||||
end
|
||||
|
||||
if self.statusBar:IsShown() then
|
||||
self:SendCommMessage(REPLY_PREFIX, profile..":NO", dist, sender)
|
||||
self:SendCommMessage(REPLY_PREFIX, profile..':NO', dist, sender)
|
||||
return
|
||||
end
|
||||
|
||||
local textString = format(L["%s is attempting to share the profile %s with you. Would you like to accept the request?"], sender, profile)
|
||||
if profile == "global" then
|
||||
if profile == 'global' then
|
||||
textString = format(L["%s is attempting to share his filters with you. Would you like to accept the request?"], sender)
|
||||
end
|
||||
|
||||
@@ -143,44 +226,40 @@ function D:OnCommReceived(prefix, msg, dist, sender)
|
||||
self.statusBar:SetValue(0)
|
||||
self.statusBar.text:SetFormattedText(L["Data From: %s"], sender)
|
||||
E:StaticPopupSpecial_Show(self.statusBar)
|
||||
self:SendCommMessage(REPLY_PREFIX, profile..":YES", dist, sender)
|
||||
self:SendCommMessage(REPLY_PREFIX, profile..':YES', dist, sender)
|
||||
end,
|
||||
OnCancel = function()
|
||||
self:SendCommMessage(REPLY_PREFIX, profile..":NO", dist, sender)
|
||||
self:SendCommMessage(REPLY_PREFIX, profile..':NO', dist, sender)
|
||||
end,
|
||||
button1 = ACCEPT,
|
||||
button2 = CANCEL,
|
||||
timeout = 32,
|
||||
timeout = 30,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1
|
||||
hideOnEscape = 1,
|
||||
}
|
||||
E:StaticPopup_Show("DISTRIBUTOR_RESPONSE")
|
||||
|
||||
E:StaticPopup_Show('DISTRIBUTOR_RESPONSE')
|
||||
|
||||
Downloads[sender] = {
|
||||
current = 0,
|
||||
length = tonumber(length),
|
||||
profile = profile
|
||||
profile = profile,
|
||||
}
|
||||
|
||||
self:RegisterComm(TRANSFER_PREFIX)
|
||||
elseif prefix == REPLY_PREFIX then
|
||||
self:UnregisterComm(REPLY_PREFIX)
|
||||
E:StaticPopup_Hide("DISTRIBUTOR_WAITING")
|
||||
|
||||
local profileKey, response = split(":", msg)
|
||||
if response == "YES" then
|
||||
self.statusBar:SetMinMaxValues(0, len(Uploads[profileKey].serialData))
|
||||
self.statusBar:SetValue(0)
|
||||
self.statusBar.text:SetFormattedText(L["Data To: %s"], sender)
|
||||
E:StaticPopupSpecial_Show(self.statusBar)
|
||||
E:StaticPopup_Hide('DISTRIBUTOR_WAITING')
|
||||
|
||||
local profileKey, response = split(':', msg)
|
||||
if response == 'YES' then
|
||||
self:RegisterComm(TRANSFER_COMPLETE_PREFIX)
|
||||
self:SendCommMessage(TRANSFER_PREFIX, Uploads[profileKey].serialData, dist, Uploads[profileKey].target, "BULK", self.UpdateSendProgress, self)
|
||||
Uploads[profileKey] = nil
|
||||
self:SendCommMessage(TRANSFER_PREFIX, Uploads[profileKey].serialData, dist, Uploads[profileKey].target)
|
||||
else
|
||||
E:StaticPopup_Show("DISTRIBUTOR_REQUEST_DENIED")
|
||||
Uploads[profileKey] = nil
|
||||
E:StaticPopup_Show('DISTRIBUTOR_REQUEST_DENIED')
|
||||
end
|
||||
|
||||
Uploads[profileKey] = nil
|
||||
elseif prefix == TRANSFER_PREFIX then
|
||||
self:UnregisterComm(TRANSFER_PREFIX)
|
||||
E:StaticPopupSpecial_Hide(self.statusBar)
|
||||
@@ -191,7 +270,7 @@ function D:OnCommReceived(prefix, msg, dist, sender)
|
||||
if success then
|
||||
local textString = format(L["Profile download complete from %s, would you like to load the profile %s now?"], sender, profileKey)
|
||||
|
||||
if profileKey == "global" then
|
||||
if profileKey == 'global' then
|
||||
textString = format(L["Filter download complete from %s, would you like to apply changes now?"], sender)
|
||||
else
|
||||
if not ElvDB.profiles[profileKey] then
|
||||
@@ -206,10 +285,10 @@ function D:OnCommReceived(prefix, msg, dist, sender)
|
||||
maxLetters = 127,
|
||||
OnAccept = function(popup)
|
||||
ElvDB.profiles[popup.editBox:GetText()] = data
|
||||
E.Libs.AceAddon:GetAddon("ElvUI").data:SetProfile(popup.editBox:GetText())
|
||||
E.Libs.AceAddon:GetAddon('ElvUI').data:SetProfile(popup.editBox:GetText())
|
||||
E:UpdateAll(true)
|
||||
-- E:StaggeredUpdateAll()
|
||||
Downloads[sender] = nil
|
||||
E:StaticPopup_Show("CONFIG_RL")
|
||||
end,
|
||||
OnShow = function(popup) popup.editBox:SetText(profileKey) popup.editBox:SetFocus() end,
|
||||
timeout = 0,
|
||||
@@ -219,8 +298,8 @@ function D:OnCommReceived(prefix, msg, dist, sender)
|
||||
preferredIndex = 3
|
||||
}
|
||||
|
||||
E:StaticPopup_Show("DISTRIBUTOR_CONFIRM")
|
||||
self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, "COMPLETE", dist, sender)
|
||||
E:StaticPopup_Show('DISTRIBUTOR_CONFIRM')
|
||||
self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, 'COMPLETE', dist, sender)
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -228,11 +307,12 @@ function D:OnCommReceived(prefix, msg, dist, sender)
|
||||
E.PopupDialogs.DISTRIBUTOR_CONFIRM = {
|
||||
text = textString,
|
||||
OnAccept = function()
|
||||
if profileKey == "global" then
|
||||
if profileKey == 'global' then
|
||||
E:CopyTable(ElvDB.global, data)
|
||||
E:UpdateAll(true)
|
||||
-- E:StaggeredUpdateAll()
|
||||
else
|
||||
E.Libs.AceAddon:GetAddon("ElvUI").data:SetProfile(profileKey)
|
||||
E.Libs.AceAddon:GetAddon('ElvUI').data:SetProfile(profileKey)
|
||||
end
|
||||
Downloads[sender] = nil
|
||||
end,
|
||||
@@ -242,123 +322,89 @@ function D:OnCommReceived(prefix, msg, dist, sender)
|
||||
button1 = YES,
|
||||
button2 = NO,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1
|
||||
hideOnEscape = 1,
|
||||
}
|
||||
|
||||
E:StaticPopup_Show("DISTRIBUTOR_CONFIRM")
|
||||
self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, "COMPLETE", dist, sender)
|
||||
E:StaticPopup_Show('DISTRIBUTOR_CONFIRM')
|
||||
self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, 'COMPLETE', dist, sender)
|
||||
else
|
||||
E:StaticPopup_Show("DISTRIBUTOR_FAILED")
|
||||
self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, "FAILED", dist, sender)
|
||||
E:StaticPopup_Show('DISTRIBUTOR_FAILED')
|
||||
self:SendCommMessage(TRANSFER_COMPLETE_PREFIX, 'FAILED', dist, sender)
|
||||
end
|
||||
elseif prefix == TRANSFER_COMPLETE_PREFIX then
|
||||
self:UnregisterComm(TRANSFER_COMPLETE_PREFIX)
|
||||
if msg == "COMPLETE" then
|
||||
E:StaticPopup_Show("DISTRIBUTOR_SUCCESS")
|
||||
if msg == 'COMPLETE' then
|
||||
E:StaticPopup_Show('DISTRIBUTOR_SUCCESS')
|
||||
else
|
||||
E:StaticPopup_Show("DISTRIBUTOR_FAILED")
|
||||
E:StaticPopup_Show('DISTRIBUTOR_FAILED')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Keys that should not be exported
|
||||
local blacklistedKeys = {
|
||||
profile = {
|
||||
general = {
|
||||
numberPrefixStyle = true,
|
||||
}
|
||||
},
|
||||
private = {},
|
||||
global = {
|
||||
general = {
|
||||
UIScale = true,
|
||||
locale = true,
|
||||
eyefinity = true,
|
||||
ignoreScalePopup = true
|
||||
},
|
||||
chat = {
|
||||
classColorMentionExcludedNames = true
|
||||
},
|
||||
unitframe = {
|
||||
spellRangeCheck = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local function GetProfileData(profileType)
|
||||
if not profileType or type(profileType) ~= "string" then
|
||||
E:Print("Bad argument #1 to 'GetProfileData' (string expected)")
|
||||
if not profileType or type(profileType) ~= 'string' then
|
||||
E:Print('Bad argument #1 to "GetProfileData" (string expected)')
|
||||
return
|
||||
end
|
||||
|
||||
local profileKey
|
||||
local profileData = {}
|
||||
|
||||
if profileType == "profile" then
|
||||
if ElvDB.profileKeys then
|
||||
profileKey = ElvDB.profileKeys[E.myname.." - "..E.myrealm]
|
||||
end
|
||||
|
||||
local profileData, profileKey = {}
|
||||
if profileType == 'profile' then
|
||||
--Copy current profile data
|
||||
profileKey = ElvDB.profileKeys and ElvDB.profileKeys[E.mynameRealm]
|
||||
profileData = E:CopyTable(profileData, ElvDB.profiles[profileKey])
|
||||
|
||||
--This table will also hold all default values, not just the changed settings.
|
||||
--This makes the table huge, and will cause the WoW client to lock up for several seconds.
|
||||
--We compare against the default table and remove all duplicates from our table. The table is now much smaller.
|
||||
profileData = E:RemoveTableDuplicates(profileData, P)
|
||||
profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.profile)
|
||||
elseif profileType == "private" then
|
||||
local privateProfileKey = E.myname.." - "..E.myrealm
|
||||
profileKey = "private"
|
||||
|
||||
profileData = E:CopyTable(profileData, ElvPrivateDB.profiles[privateProfileKey])
|
||||
profileData = E:RemoveTableDuplicates(profileData, V)
|
||||
profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.private)
|
||||
elseif profileType == "global" then
|
||||
profileKey = "global"
|
||||
|
||||
profileData = E:RemoveTableDuplicates(profileData, P, D.GeneratedKeys.profile)
|
||||
profileData = E:FilterTableFromBlacklist(profileData, D.blacklistedKeys.profile)
|
||||
elseif profileType == 'private' then
|
||||
local privateKey = ElvPrivateDB.profileKeys and ElvPrivateDB.profileKeys[E.mynameRealm]
|
||||
profileData = E:CopyTable(profileData, ElvPrivateDB.profiles[privateKey])
|
||||
profileData = E:RemoveTableDuplicates(profileData, V, D.GeneratedKeys.private)
|
||||
profileData = E:FilterTableFromBlacklist(profileData, D.blacklistedKeys.private)
|
||||
profileKey = 'private'
|
||||
elseif profileType == 'global' then
|
||||
profileData = E:CopyTable(profileData, ElvDB.global)
|
||||
profileData = E:RemoveTableDuplicates(profileData, G)
|
||||
profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.global)
|
||||
elseif profileType == "filters" then
|
||||
profileKey = "filters"
|
||||
|
||||
profileData = E:RemoveTableDuplicates(profileData, G, D.GeneratedKeys.global)
|
||||
profileData = E:FilterTableFromBlacklist(profileData, D.blacklistedKeys.global)
|
||||
profileKey = 'global'
|
||||
elseif profileType == 'filters' then
|
||||
profileData.unitframe = {}
|
||||
profileData.unitframe.aurafilters = {}
|
||||
profileData.unitframe.aurafilters = E:CopyTable(profileData.unitframe.aurafilters, ElvDB.global.unitframe.aurafilters)
|
||||
profileData.unitframe.buffwatch = {}
|
||||
profileData.unitframe.buffwatch = E:CopyTable(profileData.unitframe.buffwatch, ElvDB.global.unitframe.buffwatch)
|
||||
profileData = E:RemoveTableDuplicates(profileData, G)
|
||||
elseif profileType == "styleFilters" then
|
||||
profileKey = "styleFilters"
|
||||
|
||||
profileData.unitframe.aurafilters = E:CopyTable({}, ElvDB.global.unitframe.aurafilters)
|
||||
profileData.unitframe.aurawatch = E:CopyTable({}, ElvDB.global.unitframe.aurawatch)
|
||||
profileData = E:RemoveTableDuplicates(profileData, G, D.GeneratedKeys.global)
|
||||
profileKey = 'filters'
|
||||
elseif profileType == 'styleFilters' then
|
||||
profileKey = 'styleFilters'
|
||||
profileData.nameplates = {}
|
||||
profileData.nameplates.filters = {}
|
||||
profileData.nameplates.filters = E:CopyTable(profileData.nameplates.filters, ElvDB.global.nameplates.filters)
|
||||
profileData = E:RemoveTableDuplicates(profileData, G)
|
||||
profileData.nameplates.filters = E:CopyTable({}, ElvDB.global.nameplates.filters)
|
||||
NP:StyleFilterClearDefaults(profileData.nameplates.filters)
|
||||
profileData = E:RemoveTableDuplicates(profileData, G, D.GeneratedKeys.global)
|
||||
end
|
||||
|
||||
return profileKey, profileData
|
||||
end
|
||||
|
||||
local function GetProfileExport(profileType, exportFormat)
|
||||
local profileExport, exportString
|
||||
local profileKey, profileData = GetProfileData(profileType)
|
||||
local profileExport
|
||||
|
||||
if not profileKey or not profileData or (profileData and type(profileData) ~= "table") then
|
||||
E:Print("Error getting data from 'GetProfileData'")
|
||||
if not profileKey or not profileData or (profileData and type(profileData) ~= 'table') then
|
||||
E:Print('Error getting data from "GetProfileData"')
|
||||
return
|
||||
end
|
||||
|
||||
if exportFormat == "text" then
|
||||
if exportFormat == 'text' then
|
||||
local serialData = D:Serialize(profileData)
|
||||
exportString = D:CreateProfileExport(serialData, profileType, profileKey)
|
||||
local compressedData = LibCompress:Compress(exportString)
|
||||
local encodedData = LibBase64:Encode(compressedData)
|
||||
profileExport = encodedData
|
||||
elseif exportFormat == "luaTable" then
|
||||
exportString = E:TableToLuaString(profileData)
|
||||
local exportString = D:CreateProfileExport(serialData, profileType, profileKey)
|
||||
local compressedData = LibDeflate:CompressDeflate(exportString, LibDeflate.compressLevel)
|
||||
local printableString = LibDeflate:EncodeForPrint(compressedData)
|
||||
profileExport = printableString and format('%s%s', EXPORT_PREFIX, printableString) or nil
|
||||
elseif exportFormat == 'luaTable' then
|
||||
local exportString = E:TableToLuaString(profileData)
|
||||
profileExport = D:CreateProfileExport(exportString, profileType, profileKey)
|
||||
elseif exportFormat == "luaPlugin" then
|
||||
elseif exportFormat == 'luaPlugin' then
|
||||
profileExport = E:ProfileTableToPluginFormat(profileData, profileType)
|
||||
end
|
||||
|
||||
@@ -366,91 +412,67 @@ local function GetProfileExport(profileType, exportFormat)
|
||||
end
|
||||
|
||||
function D:CreateProfileExport(dataString, profileType, profileKey)
|
||||
local returnString
|
||||
|
||||
if profileType == "profile" then
|
||||
returnString = format("%s::%s::%s", dataString, profileType, profileKey)
|
||||
else
|
||||
returnString = format("%s::%s", dataString, profileType)
|
||||
end
|
||||
|
||||
return returnString
|
||||
return (profileType == 'profile' and format('%s::%s::%s', dataString, profileType, profileKey)) or format('%s::%s', dataString, profileType)
|
||||
end
|
||||
|
||||
function D:GetImportStringType(dataString)
|
||||
local stringType = ""
|
||||
|
||||
if LibBase64:IsBase64(dataString) then
|
||||
stringType = "Base64"
|
||||
elseif sub(dataString, 1, 1) == "{" then --Basic check to weed out obviously wrong strings
|
||||
stringType = "Table"
|
||||
end
|
||||
|
||||
return stringType
|
||||
return (strmatch(dataString, '^'..EXPORT_PREFIX) and 'Deflate') or (strmatch(dataString, '^{') and 'Table') or ''
|
||||
end
|
||||
|
||||
function D:Decode(dataString)
|
||||
local profileInfo, profileType, profileKey, profileData
|
||||
local stringType = self:GetImportStringType(dataString)
|
||||
|
||||
if stringType == "Base64" then
|
||||
local decodedData = LibBase64:Decode(dataString)
|
||||
local decompressedData, decompressedMessage = LibCompress:Decompress(decodedData)
|
||||
if stringType == 'Deflate' then
|
||||
local data = gsub(dataString, '^'..EXPORT_PREFIX, '')
|
||||
local decodedData = LibDeflate:DecodeForPrint(data)
|
||||
local decompressed = LibDeflate:DecompressDeflate(decodedData)
|
||||
|
||||
if not decompressedData then
|
||||
E:Print("Error decompressing data:", decompressedMessage)
|
||||
if not decompressed then
|
||||
E:Print('Error decompressing data.')
|
||||
return
|
||||
end
|
||||
|
||||
local serializedData, success
|
||||
serializedData, profileInfo = E:SplitString(decompressedData, "^^::") -- "^^" indicates the end of the AceSerializer string
|
||||
serializedData, profileInfo = E:SplitString(decompressed, '^^::') -- '^^' indicates the end of the AceSerializer string
|
||||
|
||||
if not profileInfo then
|
||||
E:Print("Error importing profile. String is invalid or corrupted!")
|
||||
E:Print('Error importing profile. String is invalid or corrupted!')
|
||||
return
|
||||
end
|
||||
|
||||
serializedData = format("%s%s", serializedData, "^^") --Add back the AceSerializer terminator
|
||||
profileType, profileKey = E:SplitString(profileInfo, "::")
|
||||
serializedData = format('%s%s', serializedData, '^^') --Add back the AceSerializer terminator
|
||||
profileType, profileKey = E:SplitString(profileInfo, '::')
|
||||
success, profileData = D:Deserialize(serializedData)
|
||||
|
||||
if not success then
|
||||
E:Print("Error deserializing:", profileData)
|
||||
E:Print('Error deserializing:', profileData)
|
||||
return
|
||||
end
|
||||
elseif stringType == "Table" then
|
||||
elseif stringType == 'Table' then
|
||||
local profileDataAsString
|
||||
profileDataAsString, profileInfo = E:SplitString(dataString, "}::") -- "}::" indicates the end of the table
|
||||
profileDataAsString, profileInfo = E:SplitString(dataString, '}::') -- '}::' indicates the end of the table
|
||||
|
||||
if not profileInfo then
|
||||
E:Print("Error extracting profile info. Invalid import string!")
|
||||
E:Print('Error extracting profile info. Invalid import string!')
|
||||
return
|
||||
end
|
||||
|
||||
if not profileDataAsString then
|
||||
E:Print("Error extracting profile data. Invalid import string!")
|
||||
E:Print('Error extracting profile data. Invalid import string!')
|
||||
return
|
||||
end
|
||||
|
||||
profileDataAsString = format("%s%s", profileDataAsString, "}") --Add back the missing "}"
|
||||
profileDataAsString = gsub(profileDataAsString, "\124\124", "\124") --Remove escape pipe characters
|
||||
profileType, profileKey = E:SplitString(profileInfo, "::")
|
||||
profileDataAsString = format('%s%s', profileDataAsString, '}') --Add back the missing '}'
|
||||
profileDataAsString = gsub(profileDataAsString, '\124\124', '\124') --Remove escape pipe characters
|
||||
profileType, profileKey = E:SplitString(profileInfo, '::')
|
||||
|
||||
local func, err = loadstring(format("%s %s", "return", profileDataAsString))
|
||||
local profileMessage
|
||||
local profileToTable = loadstring(format('%s %s', 'return', profileDataAsString))
|
||||
if profileToTable then profileMessage, profileData = pcall(profileToTable) end
|
||||
|
||||
if func then
|
||||
setfenv(func, {}) -- execute code in an empty environment
|
||||
local success, res = pcall(func)
|
||||
|
||||
if success then
|
||||
profileData = res
|
||||
else
|
||||
err = res
|
||||
end
|
||||
end
|
||||
|
||||
if err then
|
||||
E:Print("Error converting lua string to table:", err)
|
||||
if profileMessage and (not profileData or type(profileData) ~= 'table') then
|
||||
E:Print('Error converting lua string to table:', profileMessage)
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -459,52 +481,46 @@ function D:Decode(dataString)
|
||||
end
|
||||
|
||||
local function SetImportedProfile(profileType, profileKey, profileData, force)
|
||||
D.profileType = nil
|
||||
D.profileKey = nil
|
||||
D.profileData = nil
|
||||
if profileType == 'profile' then
|
||||
profileData = E:FilterTableFromBlacklist(profileData, D.blacklistedKeys.profile) --Remove unwanted options from import
|
||||
|
||||
if profileType == "profile" then
|
||||
profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.profile) --Remove unwanted options from import
|
||||
if not ElvDB.profiles[profileKey] or force then
|
||||
if force and E.data.keys.profile == profileKey then
|
||||
--Overwriting an active profile doesn't update when calling SetProfile
|
||||
--So make it look like we use a different profile
|
||||
local tempKey = profileKey.."_Temp"
|
||||
E.data.keys.profile = tempKey
|
||||
E.data.keys.profile = profileKey..'_Temp'
|
||||
end
|
||||
|
||||
ElvDB.profiles[profileKey] = profileData
|
||||
|
||||
--Calling SetProfile will now update all settings correctly
|
||||
E.data:SetProfile(profileKey)
|
||||
else
|
||||
D.profileType = profileType
|
||||
D.profileKey = profileKey
|
||||
D.profileData = profileData
|
||||
E:StaticPopup_Show("IMPORT_PROFILE_EXISTS")
|
||||
|
||||
return
|
||||
E:StaticPopup_Show('IMPORT_PROFILE_EXISTS', nil, nil, {profileKey = profileKey, profileType = profileType, profileData = profileData})
|
||||
end
|
||||
elseif profileType == "private" then
|
||||
profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.private) --Remove unwanted options from import
|
||||
local pfKey = ElvPrivateDB.profileKeys[E.myname.." - "..E.myrealm]
|
||||
ElvPrivateDB.profiles[pfKey] = profileData
|
||||
E:StaticPopup_Show("IMPORT_RL")
|
||||
elseif profileType == "global" then
|
||||
profileData = E:FilterTableFromBlacklist(profileData, blacklistedKeys.global) --Remove unwanted options from import
|
||||
elseif profileType == 'private' then
|
||||
local privateKey = ElvPrivateDB.profileKeys and ElvPrivateDB.profileKeys[E.mynameRealm]
|
||||
if privateKey then
|
||||
profileData = E:FilterTableFromBlacklist(profileData, D.blacklistedKeys.private) --Remove unwanted options from import
|
||||
ElvPrivateDB.profiles[privateKey] = profileData
|
||||
E:StaticPopup_Show('IMPORT_RL')
|
||||
end
|
||||
elseif profileType == 'global' then
|
||||
profileData = E:FilterTableFromBlacklist(profileData, D.blacklistedKeys.global) --Remove unwanted options from import
|
||||
E:CopyTable(ElvDB.global, profileData)
|
||||
E:StaticPopup_Show("IMPORT_RL")
|
||||
elseif profileType == "filters" then
|
||||
E:StaticPopup_Show('IMPORT_RL')
|
||||
elseif profileType == 'filters' then
|
||||
E:CopyTable(ElvDB.global.unitframe, profileData.unitframe)
|
||||
elseif profileType == "styleFilters" then
|
||||
E:CopyTable(ElvDB.global.nameplates, profileData.nameplates)
|
||||
E:UpdateUnitFrames()
|
||||
elseif profileType == 'styleFilters' then
|
||||
E:CopyTable(ElvDB.global.nameplates, profileData.nameplates or profileData.nameplate)
|
||||
E:UpdateNamePlates()
|
||||
end
|
||||
|
||||
--Update all ElvUI modules
|
||||
E:UpdateAll(true)
|
||||
end
|
||||
|
||||
function D:ExportProfile(profileType, exportFormat)
|
||||
if not profileType or not exportFormat then
|
||||
E:Print("Bad argument to 'ExportProfile' (string expected)")
|
||||
E:Print('Bad argument to "ExportProfile" (string expected)')
|
||||
return
|
||||
end
|
||||
|
||||
@@ -516,12 +532,12 @@ end
|
||||
function D:ImportProfile(dataString)
|
||||
local profileType, profileKey, profileData = self:Decode(dataString)
|
||||
|
||||
if not profileData or type(profileData) ~= "table" then
|
||||
E:Print("Error: something went wrong when converting string to table!")
|
||||
if not profileData or type(profileData) ~= 'table' then
|
||||
E:Print('Error: something went wrong when converting string to table!')
|
||||
return
|
||||
end
|
||||
|
||||
if profileType and ((profileType == "profile" and profileKey) or profileType ~= "profile") then
|
||||
if profileType and ((profileType == 'profile' and profileKey) or profileType ~= 'profile') then
|
||||
SetImportedProfile(profileType, profileKey, profileData)
|
||||
end
|
||||
|
||||
@@ -532,28 +548,28 @@ E.PopupDialogs.DISTRIBUTOR_SUCCESS = {
|
||||
text = L["Your profile was successfully recieved by the player."],
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
button1 = OKAY
|
||||
button1 = _G.OKAY,
|
||||
}
|
||||
|
||||
E.PopupDialogs.DISTRIBUTOR_WAITING = {
|
||||
text = L["Profile request sent. Waiting for response from player."],
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
timeout = 35
|
||||
timeout = 20,
|
||||
}
|
||||
|
||||
E.PopupDialogs.DISTRIBUTOR_REQUEST_DENIED = {
|
||||
text = L["Request was denied by user."],
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
button1 = OKAY
|
||||
button1 = _G.OKAY,
|
||||
}
|
||||
|
||||
E.PopupDialogs.DISTRIBUTOR_FAILED = {
|
||||
text = L["Lord! It's a miracle! The download up and vanished like a fart in the wind! Try Again!"],
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
button1 = OKAY
|
||||
button1 = _G.OKAY,
|
||||
}
|
||||
|
||||
E.PopupDialogs.DISTRIBUTOR_RESPONSE = {}
|
||||
@@ -566,20 +582,21 @@ E.PopupDialogs.IMPORT_PROFILE_EXISTS = {
|
||||
hasEditBox = 1,
|
||||
editBoxWidth = 350,
|
||||
maxLetters = 127,
|
||||
OnAccept = function(self)
|
||||
local profileType = D.profileType
|
||||
local profileKey = self.editBox:GetText()
|
||||
local profileData = D.profileData
|
||||
SetImportedProfile(profileType, profileKey, profileData, true)
|
||||
OnAccept = function(self, data)
|
||||
SetImportedProfile(data.profileType, self.editBox:GetText(), data.profileData, true)
|
||||
end,
|
||||
EditBoxOnTextChanged = function(self)
|
||||
if self:GetText() == "" then
|
||||
if self:GetText() == '' then
|
||||
self:GetParent().button1:Disable()
|
||||
else
|
||||
self:GetParent().button1:Enable()
|
||||
end
|
||||
end,
|
||||
OnShow = function(self) self.editBox:SetText(D.profileKey) self.editBox:SetFocus() end,
|
||||
OnShow = function(self, data)
|
||||
self.editBox:SetText(data.profileKey)
|
||||
self.editBox:SetFocus()
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = true,
|
||||
preferredIndex = 3
|
||||
@@ -589,14 +606,16 @@ E.PopupDialogs.IMPORT_RL = {
|
||||
text = L["You have imported settings which may require a UI reload to take effect. Reload now?"],
|
||||
button1 = ACCEPT,
|
||||
button2 = CANCEL,
|
||||
OnAccept = ReloadUI,
|
||||
OnAccept = _G.ReloadUI,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = false,
|
||||
preferredIndex = 3
|
||||
}
|
||||
|
||||
|
||||
local function InitializeCallback()
|
||||
D:Initialize()
|
||||
end
|
||||
|
||||
E:RegisterModule(D:GetName(), InitializeCallback)
|
||||
E:RegisterModule(D:GetName(), InitializeCallback)
|
||||
|
||||
+10
-3
@@ -61,6 +61,7 @@ do
|
||||
AddOn:AddLib("EP", "LibElvUIPlugin-1.0")
|
||||
AddOn:AddLib("LSM", "LibSharedMedia-3.0")
|
||||
AddOn:AddLib("ACL", "AceLocale-3.0-ElvUI")
|
||||
AddOn:AddLib('ACH', 'LibAceConfigHelper')
|
||||
AddOn:AddLib("LAB", "LibActionButton-1.0-ElvUI")
|
||||
AddOn:AddLib("LAI", "LibAuraInfo-1.0-ElvUI", true)
|
||||
AddOn:AddLib("LBF", "LibButtonFacade", true)
|
||||
@@ -70,6 +71,7 @@ do
|
||||
AddOn:AddLib("SpellRange", "SpellRange-1.0")
|
||||
AddOn:AddLib("ItemSearch", "LibItemSearch-1.2-ElvUI")
|
||||
AddOn:AddLib("Compress", "LibCompress")
|
||||
AddOn:AddLib('Deflate', 'LibDeflate')
|
||||
AddOn:AddLib("Base64", "LibBase64-1.0-ElvUI")
|
||||
AddOn:AddLib("Translit", "LibTranslit-1.0")
|
||||
-- added on ElvUI_OptionsUI load: AceGUI, AceConfig, AceConfigDialog, AceConfigRegistry, AceDBOptions
|
||||
@@ -104,11 +106,16 @@ AddOn.Tooltip = AddOn:NewModule("Tooltip","AceTimer-3.0","AceHook-3.0","AceEvent
|
||||
AddOn.TotemBar = AddOn:NewModule("Totems","AceEvent-3.0")
|
||||
AddOn.UnitFrames = AddOn:NewModule("UnitFrames","AceTimer-3.0","AceEvent-3.0","AceHook-3.0")
|
||||
AddOn.WorldMap = AddOn:NewModule("WorldMap","AceHook-3.0","AceEvent-3.0","AceTimer-3.0")
|
||||
AddOn.MapMarkers = AddOn:NewModule("MapMarkers","AceHook-3.0","AceComm-3.0","AceSerializer-3.0")
|
||||
|
||||
do
|
||||
local arg2, arg3 = "([%(%)%.%%%+%-%*%?%[%^%$])", "%%%1"
|
||||
function AddOn:EscapeString(str)
|
||||
return gsub(str, arg2, arg3)
|
||||
local a,b,c = '','([%(%)%.%%%+%-%*%?%[%^%$])','%%%1'
|
||||
function AddOn:EscapeString(s) return gsub(s,b,c) end
|
||||
|
||||
local d = {'|[TA].-|[ta]','|c[fF][fF]%x%x%x%x%x%x','|r','^%s+','%s+$'}
|
||||
function AddOn:StripString(s, ignoreTextures)
|
||||
for i = ignoreTextures and 2 or 1, #d do s = gsub(s,d[i],a) end
|
||||
return s
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
local LibStub = _G.LibStub
|
||||
local MAJOR, MINOR = 'LibAceConfigHelper', 7
|
||||
local ACH = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
local LSM = LibStub('LibSharedMedia-3.0')
|
||||
|
||||
if not ACH then return end
|
||||
local type, pairs = type, pairs
|
||||
|
||||
local function insertWidth(opt, width)
|
||||
if type(width) == 'number' and width > 5 then
|
||||
opt.customWidth = width
|
||||
else
|
||||
opt.width = width
|
||||
end
|
||||
end
|
||||
|
||||
local function insertConfirm(opt, confirm)
|
||||
local confirmType = type(confirm)
|
||||
if confirmType == 'boolean' then
|
||||
opt.confirm = true
|
||||
elseif confirmType == 'string' then
|
||||
opt.confirm = true
|
||||
opt.confirmText = confirm
|
||||
elseif confirmType == 'function' then
|
||||
opt.confirm = confirm
|
||||
end
|
||||
end
|
||||
|
||||
function ACH:Color(name, desc, order, alpha, width, get, set, disabled, hidden)
|
||||
local optionTable = { type = 'color', name = name, desc = desc, order = order, hasAlpha = alpha, get = get, set = set, disabled = disabled, hidden = hidden }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
function ACH:Description(name, order, fontSize, image, imageCoords, imageWidth, imageHeight, width, hidden)
|
||||
local optionTable = { type = 'description', name = name or '', order = order, fontSize = fontSize, image = image, imageCoords = imageCoords, imageWidth = imageWidth, imageHeight = imageHeight, hidden = hidden }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
function ACH:Execute(name, desc, order, func, image, confirm, width, get, set, disabled, hidden)
|
||||
local optionTable = { type = 'execute', name = name, desc = desc, order = order, func = func, image = image, get = get, set = set, disabled = disabled, hidden = hidden }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
if confirm then insertConfirm(optionTable, confirm) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
function ACH:Group(name, desc, order, childGroups, get, set, disabled, hidden, func)
|
||||
return { type = 'group', childGroups = childGroups, name = name, desc = desc, order = order, set = set, get = get, hidden = hidden, disabled = disabled, func = func, args = {} }
|
||||
end
|
||||
|
||||
function ACH:Header(name, order, get, set, hidden)
|
||||
return { type = 'header', name = name or '', order = order, get = get, set = set, hidden = hidden }
|
||||
end
|
||||
|
||||
function ACH:Input(name, desc, order, multiline, width, get, set, disabled, hidden, validate)
|
||||
local optionTable = { type = 'input', name = name, desc = desc, order = order, multiline = multiline, get = get, set = set, disabled = disabled, hidden = hidden, validate = validate }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
function ACH:Select(name, desc, order, values, confirm, width, get, set, disabled, hidden)
|
||||
local optionTable = { type = 'select', name = name, desc = desc, order = order, values = values or {}, get = get, set = set, disabled = disabled, hidden = hidden }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
if confirm then insertConfirm(optionTable, confirm) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
function ACH:MultiSelect(name, desc, order, values, confirm, width, get, set, disabled, hidden)
|
||||
local optionTable = { type = 'multiselect', name = name, desc = desc, order = order, values = values or {}, get = get, set = set, disabled = disabled, hidden = hidden }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
if confirm then insertConfirm(optionTable, confirm) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
function ACH:Toggle(name, desc, order, tristate, confirm, width, get, set, disabled, hidden)
|
||||
local optionTable = { type = 'toggle', name = name, desc = desc, order = order, tristate = tristate, get = get, set = set, disabled = disabled, hidden = hidden }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
if confirm then insertConfirm(optionTable, confirm) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
-- Values are the following: key = value
|
||||
-- min - min value
|
||||
-- max - max value
|
||||
-- softMin - 'soft' minimal value, used by the UI for a convenient limit while allowing manual input of values up to min/max
|
||||
-- softMax - 'soft' maximal value, used by the UI for a convenient limit while allowing manual input of values up to min/max
|
||||
-- step - step value: 'smaller than this will break the code' (default=no stepping limit)
|
||||
-- bigStep - a more generally-useful step size. Support in UIs is optional.
|
||||
-- isPercent (boolean) - represent e.g. 1.0 as 100%, etc. (default=false)
|
||||
|
||||
function ACH:Range(name, desc, order, values, width, get, set, disabled, hidden)
|
||||
local optionTable = { type = 'range', name = name, desc = desc, order = order, get = get, set = set, disabled = disabled, hidden = hidden }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
if values and type(values) == 'table' then
|
||||
for key, value in pairs(values) do
|
||||
optionTable[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
function ACH:Spacer(order, width, hidden)
|
||||
local optionTable = { name = ' ', type = 'description', order = order, hidden = hidden }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
local function SharedMediaSelect(controlType, name, desc, order, values, width, get, set, disabled, hidden)
|
||||
local optionTable = { type = 'select', dialogControl = controlType, name = name, desc = desc, order = order, values = values, get = get, set = set, disabled = disabled, hidden = hidden }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
|
||||
function ACH:SharedMediaFont(name, desc, order, width, get, set, disabled, hidden)
|
||||
return SharedMediaSelect('LSM30_Font', name, desc, order, function() return LSM:HashTable('font') end, width, get, set, disabled, hidden)
|
||||
end
|
||||
|
||||
function ACH:SharedMediaSound(name, desc, order, width, get, set, disabled, hidden)
|
||||
return SharedMediaSelect('LSM30_Sound', name, desc, order, function() return LSM:HashTable('sound') end, width, get, set, disabled, hidden)
|
||||
end
|
||||
|
||||
function ACH:SharedMediaStatusbar(name, desc, order, width, get, set, disabled, hidden)
|
||||
return SharedMediaSelect('LSM30_Statusbar', name, desc, order, function() return LSM:HashTable('statusbar') end, width, get, set, disabled, hidden)
|
||||
end
|
||||
|
||||
function ACH:SharedMediaBackground(name, desc, order, width, get, set, disabled, hidden)
|
||||
return SharedMediaSelect('LSM30_Background', name, desc, order, function() return LSM:HashTable('background') end, width, get, set, disabled, hidden)
|
||||
end
|
||||
|
||||
function ACH:SharedMediaBorder(name, desc, order, width, get, set, disabled, hidden)
|
||||
return SharedMediaSelect('LSM30_Border', name, desc, order, function() return LSM:HashTable('border') end, width, get, set, disabled, hidden)
|
||||
end
|
||||
|
||||
local FontFlagValues = {
|
||||
NONE = 'None',
|
||||
OUTLINE = 'Outline',
|
||||
THICKOUTLINE = 'Thick',
|
||||
MONOCHROME = '|cffaaaaaaMono|r',
|
||||
MONOCHROMEOUTLINE = '|cffaaaaaaMono|r Outline',
|
||||
MONOCHROMETHICKOUTLINE = '|cffaaaaaaMono|r Thick',
|
||||
}
|
||||
|
||||
function ACH:FontFlags(name, desc, order, width, get, set, disabled, hidden)
|
||||
local optionTable = { type = 'select', name = name, desc = desc, order = order, get = get, set = set, disabled = disabled, hidden = hidden, values = FontFlagValues }
|
||||
|
||||
if width then insertWidth(optionTable, width) end
|
||||
|
||||
return optionTable
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
zlib License
|
||||
|
||||
(C) 2018-2021 Haoqian He
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,10 @@
|
||||
<Include file="Ace3\AceComm-3.0\AceComm-3.0.xml"/>
|
||||
<Include file="Ace3\AceSerializer-3.0\AceSerializer-3.0.xml"/>
|
||||
<Script file="LibSharedMedia-3.0\LibSharedMedia-3.0.lua"/>
|
||||
<!-- -->
|
||||
<Script file='LibAceConfigHelper\LibAceConfigHelper.lua'/>
|
||||
<Script file='LibDeflate\LibDeflate.lua'/>
|
||||
<!-- -->
|
||||
<Script file="LibSimpleSticky\LibSimpleSticky.lua"/>
|
||||
<Script file="LibSpellRange-1.0\LibSpellRange-1.0.lua"/>
|
||||
<Script file="HealPredict\healpredict.lua"/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||||
<Script file="Minimap.lua"/>
|
||||
<Script file="Worldmap.lua"/>
|
||||
<Script file="MapMarkers.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,190 @@
|
||||
local E, L, V, P, G = unpack(select(2, ...)) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
|
||||
-- local MM = {}
|
||||
local MM = E:GetModule("MapMarkers")
|
||||
local ElvUI_AllMarkers = {};
|
||||
local ElvUI_ShowedMarkers = {};
|
||||
local debug = false
|
||||
-- local _print = print
|
||||
local dprint = function(...)
|
||||
if debug then print(...) end
|
||||
end
|
||||
|
||||
local IgnoreList = {};
|
||||
|
||||
-- LibStub("AceComm-3.0"):Embed(MM);
|
||||
-- LibStub("AceSerializer-3.0"):Embed(MM);
|
||||
local coords = {0.499, 0.751, 0.276, 0.484};
|
||||
-- local mapX,mapY = WorldMapButton:GetSize()
|
||||
local prefix = "ElvUI_Marker";
|
||||
local texturePath = "Interface\\AddOns\\ElvUI\\Media\\Textures\\RaidIcons";
|
||||
|
||||
|
||||
local SYNC_INFO = "|Hplayer:%1$s|h[%1$s]|h Places a marker on the map " ..
|
||||
": \n|Helvm:show:%2$s:%3$s:%4$s:nil|h|cff3588ff[Show Location]|r|h |Helvm:ignore:%1$s|h|cff3588ff[Ignore markers from: %1$s]|r|h"
|
||||
|
||||
function MM:SendMark(text, distribution)
|
||||
MM:SendCommMessage(prefix, text, distribution or "RAID");
|
||||
end
|
||||
local pname = UnitName("player");
|
||||
|
||||
function MM:ReseiveMark(text, distribution, target)
|
||||
|
||||
local success,mapid, x, y, who = MM:Deserialize(text);
|
||||
mapid = tonumber(mapid)
|
||||
if success and mapid and x and y and who ~= pname and not IgnoreList[who] then
|
||||
MM:PrintMarkInfo(mapid, x, y, who);
|
||||
end
|
||||
end
|
||||
function MM:PrintMarkInfo(mapid, x, y, who)
|
||||
DEFAULT_CHAT_FRAME:AddMessage(string.format(SYNC_INFO,who,mapid,x,y), 0.41, 0.8, 0.94);
|
||||
end
|
||||
function MM:HideAll()
|
||||
for i = 1, #ElvUI_ShowedMarkers do
|
||||
ElvUI_ShowedMarkers[i]:Hide();
|
||||
end
|
||||
table.wipe(ElvUI_ShowedMarkers);
|
||||
end
|
||||
|
||||
function MM:ShowMark(i,mapid)
|
||||
local marker = ElvUI_AllMarkers[mapid][i];
|
||||
|
||||
if marker.showed then
|
||||
marker:Show()
|
||||
table.insert(ElvUI_ShowedMarkers, marker);
|
||||
elseif not marker.showed then
|
||||
marker:Hide()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function MM:CreateMark(mapid,IsSendedMark,x,y)
|
||||
|
||||
mapid = mapid or GetCurrentMapAreaID();
|
||||
mapid = tonumber(mapid)
|
||||
if not WorldMapFrame:IsShown() and IsSendedMark then
|
||||
ToggleFrame(WorldMapFrame)
|
||||
SetMapByID(mapid-1)
|
||||
end
|
||||
local curX, curY = GetCursorPosition();
|
||||
local scale = WorldMapDetailFrame:GetEffectiveScale();
|
||||
local width, height = WorldMapDetailFrame:GetSize();
|
||||
local centerX, centerY = WorldMapDetailFrame:GetCenter();
|
||||
local adjustedX = (curX / scale - (centerX - (width * 0.5))) / width;
|
||||
local adjustedY = (centerY + (height * 0.5) - curY / scale) / height;
|
||||
x = IsSendedMark and x or adjustedX * 100;
|
||||
y = IsSendedMark and y or adjustedY * 100;
|
||||
ElvUI_AllMarkers[mapid] = ElvUI_AllMarkers[mapid] or {};
|
||||
|
||||
local lastIndex = #ElvUI_AllMarkers[mapid];
|
||||
ElvUI_AllMarkers[mapid][lastIndex+1] = CreateFrame("Frame", "Marker"..mapid..lastIndex+1, WorldMapDetailFrame);
|
||||
local marker = ElvUI_AllMarkers[mapid][lastIndex+1];
|
||||
marker.name = "Marker"..mapid..lastIndex;
|
||||
marker.index = lastIndex+1;
|
||||
marker.x = x;
|
||||
marker.y = y;
|
||||
marker.Texture = marker:CreateTexture();
|
||||
marker.Texture:SetTexture(texturePath);
|
||||
marker.Texture:SetAllPoints();
|
||||
marker.Texture:SetTexCoord(unpack(coords))
|
||||
marker:SetPoint("CENTER", WorldMapDetailFrame, "TOPLEFT", (x / 100) * WorldMapDetailFrame:GetWidth(), (-y / 100) * WorldMapDetailFrame:GetHeight());
|
||||
marker:SetWidth(31);
|
||||
marker:SetHeight(31);
|
||||
marker:SetFrameStrata("DIALOG");
|
||||
marker:EnableMouse(true);
|
||||
marker:HookScript("OnEnter", function(self)
|
||||
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
|
||||
GameTooltip:SetText("SHIFT + ПКМ убрать метку", 1, 1, 1)
|
||||
GameTooltip:Show()
|
||||
end)
|
||||
marker:SetScript("OnLeave", function()
|
||||
GameTooltip:Hide()
|
||||
end)
|
||||
marker:SetScript("OnMouseDown",function(self,click)
|
||||
if IsShiftKeyDown() and click == "MiddleButton" then
|
||||
self:Hide();
|
||||
self.showed = false;
|
||||
MM:RefreshAll();
|
||||
end
|
||||
end)
|
||||
marker.showed = true;
|
||||
table.insert(ElvUI_ShowedMarkers, marker);
|
||||
marker:Show();
|
||||
if IsSendedMark then
|
||||
local mname = GetMapName(mapid) or (mapid .." (mapid)")
|
||||
print(format("Map marker added in %s at (%.1f, %.1f)", mname, x, y))
|
||||
else
|
||||
MM:SendMark(MM:Serialize(mapid, x, y, pname));
|
||||
end
|
||||
end
|
||||
|
||||
function MM:RefreshAll()
|
||||
MM:HideAll();
|
||||
local mapid = GetCurrentMapAreaID();
|
||||
mapid = tonumber(mapid)
|
||||
ElvUI_AllMarkers[mapid] = ElvUI_AllMarkers[mapid] or {};
|
||||
local leng = #ElvUI_AllMarkers[mapid];
|
||||
if leng and leng > 0 then
|
||||
for i = 1, leng do
|
||||
MM:ShowMark(i,mapid);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function createMark(self, link)
|
||||
local _,_, mapid, x, y = strsplit(":", link);
|
||||
mapid = tonumber(mapid)
|
||||
MM:CreateMark(mapid,true,x,y);
|
||||
end
|
||||
local function AddToIgnore(self,link)
|
||||
local _,_, name = strsplit(":", link);
|
||||
-- MM:CreateMark(mapid,true,x,y)
|
||||
IgnoreList[name] = true;
|
||||
print(name.." was added to ignored markers list.");
|
||||
end
|
||||
function MM:Initialize()
|
||||
if not E.db.general.mapMarkers.enable then return end
|
||||
|
||||
local _SetItemRef = SetItemRef
|
||||
function SetItemRef(link, textref, button, chatFrame)
|
||||
if link:match("elvm:show") then
|
||||
createMark(chatFrame,link);
|
||||
elseif link:match("elvm:ignore") then
|
||||
AddToIgnore(chatFrame,link);
|
||||
else
|
||||
_SetItemRef(link, textref, button, chatFrame);
|
||||
end
|
||||
end
|
||||
|
||||
WorldMapButton:RegisterForClicks("LeftButtonDownm", "RightButtonDown","MiddleButtonDown");
|
||||
WorldMapButton:HookScript("OnClick",function(self,click)
|
||||
if click == "MiddleButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then
|
||||
MM:CreateMark(nil,false);
|
||||
end
|
||||
end)
|
||||
|
||||
local function EventHandler(self, event, ...)
|
||||
MM:RefreshAll();
|
||||
end
|
||||
MM.imFrame = CreateFrame("Frame",nil,UIParent);
|
||||
|
||||
MM.imFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
|
||||
MM.imFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA");
|
||||
MM.imFrame:RegisterEvent("WORLD_MAP_UPDATE");
|
||||
MM.imFrame:RegisterEvent("WORLD_MAP_NAME_UPDATE");
|
||||
MM.imFrame:SetScript("OnEvent", EventHandler);
|
||||
|
||||
if E.db.general.mapMarkers.showRaidMarkers then
|
||||
MM:RegisterComm(prefix, MM.ReseiveMark);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function InitializeCallback()
|
||||
MM:Initialize()
|
||||
end
|
||||
|
||||
E:RegisterInitialModule(MM:GetName(), InitializeCallback)
|
||||
|
||||
|
||||
|
||||
@@ -95,13 +95,6 @@ local menuList = {
|
||||
ToggleFrame(AscensionLFGFrame)
|
||||
end
|
||||
},
|
||||
-- {
|
||||
-- text = LOOKING_FOR_RAID,
|
||||
-- notCheckable = 1,
|
||||
-- func = function()
|
||||
-- ToggleFrame(LFRParentFrame)
|
||||
-- end
|
||||
-- },
|
||||
{
|
||||
text = MAINMENU_BUTTON,
|
||||
notCheckable = 1,
|
||||
|
||||
@@ -14,11 +14,6 @@ function D:ModifyErrorFrame()
|
||||
|
||||
local Orig_ScriptErrorsFrame_Update = ScriptErrorsFrame_Update
|
||||
ScriptErrorsFrame_Update = function(...)
|
||||
if GetCVarBool("scriptErrors") ~= 1 then
|
||||
Orig_ScriptErrorsFrame_Update(...)
|
||||
return
|
||||
end
|
||||
|
||||
-- Sometimes the locals table does not have an entry for an index, which can cause an argument #6 error
|
||||
-- in Blizzard_DebugTools.lua:430 and then cause a C stack overflow, this will prevent that
|
||||
local index = ScriptErrorsFrame.index
|
||||
@@ -32,8 +27,10 @@ function D:ModifyErrorFrame()
|
||||
|
||||
Orig_ScriptErrorsFrame_Update(...)
|
||||
|
||||
-- Stop text highlighting again
|
||||
ScriptErrorsFrameScrollFrameText:HighlightText(0, 0)
|
||||
if GetCVarBool("scriptErrors") == 1 then
|
||||
-- Stop text highlighting again
|
||||
ScriptErrorsFrameScrollFrameText:HighlightText(0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Unhighlight text when focus is hit
|
||||
@@ -42,9 +39,9 @@ function D:ModifyErrorFrame()
|
||||
end)
|
||||
|
||||
ScriptErrorsFrame:Size(500, 300)
|
||||
ScriptErrorsFrameScrollFrame:Size(ScriptErrorsFrame:GetWidth() - 45, ScriptErrorsFrame:GetHeight() - 71)
|
||||
ScriptErrorsFrameScrollFrame:Size(455, 229)
|
||||
|
||||
ScriptErrorsFrameScrollFrameText:Width(ScriptErrorsFrameScrollFrame:GetWidth())
|
||||
ScriptErrorsFrameScrollFrameText:Width(455)
|
||||
|
||||
local BUTTON_WIDTH = 75
|
||||
local BUTTON_HEIGHT = 24
|
||||
@@ -62,6 +59,17 @@ function D:ModifyErrorFrame()
|
||||
end)
|
||||
ScriptErrorsFrame.firstButton = firstButton
|
||||
|
||||
-- add reload button
|
||||
local reloadButton = CreateFrame("Button", nil, ScriptErrorsFrame, "UIPanelButtonTemplate")
|
||||
reloadButton:SetPoint("LEFT", firstButton, "LEFT", -30, 0)
|
||||
reloadButton:SetText("R")
|
||||
reloadButton:SetHeight(BUTTON_HEIGHT)
|
||||
reloadButton:SetWidth(30)
|
||||
reloadButton:SetScript("OnClick", function()
|
||||
ReloadUI()
|
||||
end)
|
||||
ScriptErrorsFrame.reloadButton = reloadButton
|
||||
|
||||
-- Also add a Last button for errors
|
||||
local lastButton = CreateFrame("Button", nil, ScriptErrorsFrame, "UIPanelButtonTemplate")
|
||||
lastButton:SetPoint("BOTTOMLEFT", ScriptErrorsFrame.next, "BOTTOMRIGHT", BUTTON_SPACING, 0)
|
||||
|
||||
@@ -84,6 +84,10 @@ P.general = {
|
||||
}
|
||||
}
|
||||
},
|
||||
mapMarkers = {
|
||||
enable = true,
|
||||
showRaidMarkers = true,
|
||||
},
|
||||
threat = {
|
||||
enable = true,
|
||||
position = "RIGHTCHAT",
|
||||
|
||||
@@ -2,7 +2,7 @@ local E = unpack(ElvUI) --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalD
|
||||
local D = E:GetModule("Distributor")
|
||||
|
||||
local _, Engine = ...
|
||||
Engine[1] = {}
|
||||
Engine[1] = {Blank = function() return '' end }
|
||||
Engine[2] = E.Libs.ACL:GetLocale("ElvUI", E.global.general.locale or "enUS")
|
||||
local C, L = Engine[1], Engine[2]
|
||||
|
||||
@@ -48,7 +48,7 @@ E.Options.args = {
|
||||
width = "full"
|
||||
},
|
||||
RepositionWindow = {
|
||||
order = 2,
|
||||
order = 3,
|
||||
type = "execute",
|
||||
name = L["Reposition Window"],
|
||||
desc = L["Reset the size and position of this frame."],
|
||||
@@ -58,7 +58,7 @@ E.Options.args = {
|
||||
end
|
||||
},
|
||||
ToggleTutorial = {
|
||||
order = 3,
|
||||
order = 4,
|
||||
type = "execute",
|
||||
name = L["Toggle Tutorials"],
|
||||
customWidth = 150,
|
||||
@@ -68,7 +68,7 @@ E.Options.args = {
|
||||
end
|
||||
},
|
||||
Install = {
|
||||
order = 4,
|
||||
order = 5,
|
||||
type = "execute",
|
||||
name = L["Install"],
|
||||
customWidth = 100,
|
||||
@@ -79,7 +79,7 @@ E.Options.args = {
|
||||
end
|
||||
},
|
||||
ResetAllMovers = {
|
||||
order = 5,
|
||||
order = 6,
|
||||
type = "execute",
|
||||
name = L["Reset Anchors"],
|
||||
customWidth = 150,
|
||||
@@ -89,7 +89,7 @@ E.Options.args = {
|
||||
end
|
||||
},
|
||||
ToggleAnchors = {
|
||||
order = 6,
|
||||
order = 7,
|
||||
type = "execute",
|
||||
name = L["Toggle Anchors"],
|
||||
customWidth = 150,
|
||||
@@ -99,7 +99,7 @@ E.Options.args = {
|
||||
end
|
||||
},
|
||||
LoginMessage = {
|
||||
order = 7,
|
||||
order = 8,
|
||||
type = "toggle",
|
||||
name = L["Login Message"],
|
||||
customWidth = 150,
|
||||
|
||||
@@ -24,4 +24,5 @@ UnitFrames.lua
|
||||
DataBars.lua
|
||||
Maps.lua
|
||||
ModuleControl.lua
|
||||
Tags.lua
|
||||
Tags.lua
|
||||
Search.lua
|
||||
@@ -120,6 +120,37 @@ E.Options.args.maps = {
|
||||
min = -200, max = 200, step = 1
|
||||
}
|
||||
}
|
||||
},
|
||||
spacer2 = {
|
||||
order = 6,
|
||||
type = "description",
|
||||
name = "\n"
|
||||
},
|
||||
mapMarkersGroup = {
|
||||
order = 7,
|
||||
type = "group",
|
||||
name = L["Map Markers"],
|
||||
guiInline = true,
|
||||
disabled = function() return not WM.Initialized end,
|
||||
args = {
|
||||
enable = {
|
||||
order = 1,
|
||||
type = "toggle",
|
||||
name = L["Enable"],
|
||||
desc = L["Map Markers on map"],
|
||||
get = function(info) return E.db.general.mapMarkers[info[#info]] end,
|
||||
set = function(info, value) E.db.general.mapMarkers[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end
|
||||
},
|
||||
showRaidMarkers = {
|
||||
order = 2,
|
||||
type = "toggle",
|
||||
name = L["Reseive Raid Markers from raid"],
|
||||
desc = L["Reseive Raid Markers from raid"],
|
||||
get = function(info) return E.db.general.mapMarkers[info[#info]] end,
|
||||
set = function(info, value) E.db.general.mapMarkers[info[#info]] = value E:StaticPopup_Show("PRIVATE_RL") end,
|
||||
disabled = function() return not E.db.general.mapMarkers.enable end,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
local E, _, V, P, G = unpack(ElvUI)
|
||||
local C, L = unpack(select(2, ...))
|
||||
local ACH = E.Libs.ACH
|
||||
local SearchText = ''
|
||||
|
||||
local gsub = gsub
|
||||
local wipe = wipe
|
||||
local next = next
|
||||
local type = type
|
||||
local pcall = pcall
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local gmatch = gmatch
|
||||
local tinsert = tinsert
|
||||
local strtrim = strtrim
|
||||
local strfind = strfind
|
||||
local strjoin = strjoin
|
||||
local strlower = strlower
|
||||
local strmatch = strmatch
|
||||
local strsplit = strsplit
|
||||
|
||||
local start = 100
|
||||
local depth = start + 2
|
||||
local inline = depth - 1
|
||||
local results, entries = {}, {}
|
||||
local sep = ' |cFF888888>|r '
|
||||
|
||||
local searchCache = {}
|
||||
local blockOption = {
|
||||
filters = true,
|
||||
info = true,
|
||||
plugins = true,
|
||||
search = true,
|
||||
tagGroup = true,
|
||||
modulecontrol = true,
|
||||
profiles = true
|
||||
}
|
||||
|
||||
local typeInvalid = {
|
||||
description = true,
|
||||
header = true
|
||||
}
|
||||
|
||||
local typeValue = {
|
||||
multiselect = true,
|
||||
select = true,
|
||||
}
|
||||
|
||||
local nameIndex = {
|
||||
[L["General"]] = 1,
|
||||
[L["Global"]] = 0
|
||||
}
|
||||
|
||||
E.Options.args.search = ACH:Group(L["Search"], nil, 4)
|
||||
local Search = E.Options.args.search.args
|
||||
|
||||
local EditBox = ACH:Input(L["Search"], nil, 0, nil, 1.5, function() return SearchText end, function(_, value) C:Search_ClearResults() if strmatch(value, '%S+') then SearchText = strtrim(strlower(value)) C:Search_Config() C:Search_AddResults() end end)
|
||||
-- Search.editbox = EditBox
|
||||
|
||||
E.Options.args.searchEditBox = EditBox
|
||||
E.Options.args.searchEditBox.order = 2
|
||||
|
||||
local Header = {
|
||||
order = 1,
|
||||
type = "header",
|
||||
name = "Enter configuration options to search for in the top left of the options window.\nResults will be shown on the left under the \"Search\" category",
|
||||
width = "full"
|
||||
}
|
||||
local Header2 = {
|
||||
order = 2,
|
||||
type = "header",
|
||||
name = "The results will be shown under the search category on the left",
|
||||
width = "full"
|
||||
}
|
||||
Search.header = Header
|
||||
Search.header2 = Header2
|
||||
-- E.Options.args.searchEditBox.height = 20
|
||||
-- local WhatsNew = ACH:Execute(L["Whats New"], nil, 1, function() C:Search_ClearResults() C:Search_Config(nil, nil, nil, true) C:Search_AddResults() end, nil, nil, nil, nil, nil, nil, function() return SearchText ~= '' or next(searchCache) end)
|
||||
-- Search.whatsNew = WhatsNew
|
||||
|
||||
function C:Search_DisplayResults(groups, section)
|
||||
if groups.entries then
|
||||
groups.entries.section = section
|
||||
end
|
||||
|
||||
local index = groups.index or start
|
||||
groups.index = nil
|
||||
|
||||
for name, group in pairs(groups) do
|
||||
if name ~= 'entries' then
|
||||
local sub = ACH:Group(name, nil, nameIndex[name] or index, 'tab')
|
||||
sub.inline = index == inline
|
||||
section[name] = sub
|
||||
|
||||
C:Search_DisplayResults(group, sub.args)
|
||||
end
|
||||
end
|
||||
|
||||
if groups.entries then
|
||||
C:Search_DisplayButtons(groups.entries)
|
||||
end
|
||||
end
|
||||
|
||||
function C:Search_ButtonFunc()
|
||||
if self.option then
|
||||
E.Libs.AceConfigDialog:SelectGroup('ElvUI', strsplit(',', self.option.location))
|
||||
end
|
||||
end
|
||||
|
||||
function C:Search_DisplayButtons(buttons)
|
||||
local section = buttons.section
|
||||
buttons.section = nil
|
||||
|
||||
for _, data in next, buttons do
|
||||
local button = ACH:Execute(data.clean, nil, nil, C.Search_ButtonFunc, nil, nil, 1.5)
|
||||
button.location = data.location
|
||||
section[data.name] = button
|
||||
end
|
||||
end
|
||||
|
||||
function C:Search_AddButton(location, name)
|
||||
local group, index, clean = results, start, name
|
||||
for groupName in gmatch(name, '(.-)'..sep) do
|
||||
if index > depth then break end
|
||||
|
||||
-- button name
|
||||
clean = gsub(clean, '^' .. E:EscapeString(groupName) .. sep, '')
|
||||
|
||||
-- sub groups
|
||||
if not group[groupName] then group[groupName] = { index = index } end
|
||||
group = group[groupName]
|
||||
|
||||
index = index + 1
|
||||
end
|
||||
|
||||
-- sub buttons
|
||||
local count, entry = (entries.count or 0) + 1, { name = name, clean = clean, location = location }
|
||||
entries.count, entries[count] = count, entry
|
||||
|
||||
-- linking
|
||||
if not group.entries then group.entries = {} end
|
||||
group.entries[count] = entry
|
||||
end
|
||||
|
||||
function C:Search_AddResults()
|
||||
wipe(results)
|
||||
wipe(entries)
|
||||
|
||||
for location, names in pairs(searchCache) do
|
||||
if type(names) == 'table' then
|
||||
for _, name in ipairs(names) do
|
||||
C:Search_AddButton(location, name)
|
||||
end
|
||||
else
|
||||
C:Search_AddButton(location, names)
|
||||
end
|
||||
end
|
||||
|
||||
C:Search_DisplayResults(results, Search)
|
||||
end
|
||||
|
||||
function C:Search_ClearResults()
|
||||
wipe(searchCache)
|
||||
wipe(Search)
|
||||
Search.header = Header
|
||||
Search.header2 = Header2
|
||||
-- Search.editbox = EditBox
|
||||
-- Search.whatsNew = WhatsNew
|
||||
SearchText = ''
|
||||
end
|
||||
|
||||
function C:Search_FindText(text, whatsNew)
|
||||
if whatsNew then
|
||||
return strfind(text, E.NewSign, nil, true)
|
||||
else
|
||||
return strfind(strlower(E:StripString(text)), SearchText, nil, true)
|
||||
end
|
||||
end
|
||||
|
||||
function C:Search_GetReturn(value, ...)
|
||||
if type(value) == 'function' then
|
||||
local success, arg1 = pcall(value, ...)
|
||||
if success then
|
||||
return arg1
|
||||
end
|
||||
else
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
function C:Search_Config(tbl, loc, locName, whatsNew)
|
||||
if not whatsNew and SearchText == '' then return end
|
||||
|
||||
for option, infoTable in pairs(tbl or E.Options.args) do
|
||||
if not (blockOption[option] or infoTable.hidden or typeInvalid[infoTable.type]) then
|
||||
local location, locationName = loc and (infoTable.type == 'group' and not infoTable.inline and strjoin(',', loc, option) or loc) or option
|
||||
local name = C:Search_GetReturn(infoTable.name, option)
|
||||
if type(name) == 'string' then -- bad apples
|
||||
locationName = locName and (strmatch(name, '%S+') and strjoin(sep, locName, name) or locName) or name
|
||||
if C:Search_FindText(name, whatsNew) then
|
||||
if not searchCache[location] then
|
||||
searchCache[location] = locationName
|
||||
elseif type(searchCache[location]) == 'table' then
|
||||
tinsert(searchCache[location], locationName)
|
||||
else
|
||||
searchCache[location] = { searchCache[location], locationName }
|
||||
end
|
||||
else
|
||||
local values = (typeValue[infoTable.type] and not infoTable.dialogControl) and C:Search_GetReturn(infoTable.values, option)
|
||||
if values then
|
||||
for _, subName in next, values do
|
||||
if type(subName) == 'string' and C:Search_FindText(subName, whatsNew) then
|
||||
searchCache[location] = locationName
|
||||
break -- only need one
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- process objects (sometimes without a locationName)
|
||||
if type(infoTable) == 'table' and infoTable.args then
|
||||
C:Search_Config(infoTable.args, location, locationName, whatsNew)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user