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:
fxpw(Toxa)
2023-01-07 12:46:08 +03:00
committed by GitHub
parent 8826ee51bf
commit f097d91fb1
16 changed files with 4507 additions and 296 deletions
+3 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
+19
View File
@@ -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
+4
View File
@@ -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
View File
@@ -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>
+190
View File
@@ -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)
-7
View File
@@ -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,
+17 -9
View File
@@ -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)
+4
View File
@@ -84,6 +84,10 @@ P.general = {
}
}
},
mapMarkers = {
enable = true,
showRaidMarkers = true,
},
threat = {
enable = true,
position = "RIGHTCHAT",
+7 -7
View File
@@ -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,
+2 -1
View File
@@ -24,4 +24,5 @@ UnitFrames.lua
DataBars.lua
Maps.lua
ModuleControl.lua
Tags.lua
Tags.lua
Search.lua
+31
View File
@@ -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,
},
}
}
}
},
+227
View File
@@ -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