9 Commits
Author SHA1 Message Date
Lothar Buchholz 8feea49c36 Version 1.1.7
- messages during encounters are sent unchanged, with a one-time notice
- handling of german umlauts (and other unicode characters)
- updated libraries and bumped version for all incarnations of WoW (Classic Era, Forever, Classic, Retail)
- adaptations to Retail v12 new Chat handling (API changes, encounter lockdown, instance chat)
- "/r" no longer sends to an empty whisper target if the last told target is unavailable
- fixed replacements in instance chats
- messages to unknown numbered channels are now discarded
- right-click on the minimap button
2026-11-01 16:06:37 +01:00
Lothar Buchholz a706241a90 - fixes german umlauts 2026-11-01 16:05:54 +01:00
Lothar Buchholz 2e476648dd - adapted to new Chat API
- fixed broken size calucation
- fixed Import message
2026-11-01 15:37:09 +01:00
Lothar Buchholz 37e3dbe63d - consolidated changelog and updated gitignore 2026-11-01 01:03:16 +01:00
Lothar Buchholz 01931510eb - switching to new C_AddOns API changes
- cascaded message hooking for Retail v12 engine
- messages during encounters are sent unchanged, with a one-time notice
- ignore numbered chats that do not exist
- /r no longer sends to an empty whisper target if the last told target is unavailable
- fixed replacements in instance chats
- messages to unknown numbered channels are now discarded
- right-click on the minimap button
2026-11-01 00:57:12 +01:00
Lothar Buchholz 79873b0523 - updated all libraries 2026-11-01 00:07:10 +01:00
Lothar Buchholz e077eca0bd - TOC update 2026-10-31 23:54:14 +01:00
Lothar Buchholz ba160aface - restored previous changes; cleanup workspace 2026-10-31 23:53:44 +01:00
Lothar Buchholz 396e140102 Version 1.1.6
- bumped version for latest WotLK Classic patch
- updated Ace3.0 libraries for latest WotLK Classic patch
2023-01-18 19:47:41 +01:00
33 changed files with 1222 additions and 473 deletions
+114 -34
View File
@@ -1,44 +1,124 @@
# Gradle ### Artifacts ###
.gradle # Compilation
build/
# Android built artifacts
*.apk
*.ap_
*.dex
# Java build artifacts class files
*.class *.class
# other generated files # Package Files
gen/ *.jar
*.war
*.nar
*.ear
### Maven ###
pom.xml.*
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
target/ target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
# local configuration file (for Android sdk path, etc) ### Java ###
local.properties
# OSX files # Mobile Tools for Java (J2ME)
.DS_Store .mtj.tmp/
# Eclipse # crash logs and heap dumps
/.classpath hs_err_pid*
/.settings/ replay_pid*
/.project
/.metadata
bin/
# IntelliJ ### Backup ###
*.iws *.bak
*.uml *.ori
.idea/ *.orig
out/ *.tmp
*.zip
*.tar.gz
*.rar
# NDK ### CREDENTIALS ###
obj/
# Misc **/secret
.bin/
.release/ ### LOCAL-DEV ###
*-local.xml
*-local.yml
*-local.yaml
*-settings.*
drivers/*.jar
*.log *.log
*.graphml
coverage.db* ### IntelliJ ###
.idea/
*.iws
*.iml
*.ipr
out/
!.idea/**/vcs.xml
!.idea/**/encodings.xml
### Eclipse ###
.apt_generated
.classpath
.factorypath
.metadata
.project
.classpath
.settings/
.springBeans
.sts4-cache
/bin/
/tmp/
*.swp
*~.nib
### NetBeans ###
**/nbproject/*
build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
.history/
*.vsix
### Windows ###
Thumbs.db
[Dd]esktop.ini
*.lnk
### Linux ###
*~
.fuse_hidden*
.directory
.Trash-*
.nfs*
### MacOS ###
.DS_Store
.AppleDouble
.LSOverride
### AI harness ###
.claude/
.codex/
### Lokale Umgebung ###
.env
.env.*
!.env.example
+19
View File
@@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Version 1.1.7 - 2026-11-01
### Added
- messages during encounters are sent unchanged, with a one-time notice
### Changed
- handling of german umlauts (and other unicode characters)
- updated libraries and bumped version for all incarnations of WoW (Classic Era, Forever, Classic, Retail)
- adaptations to Retail v12 new Chat handling (API changes, encounter lockdown, instance chat)
### Fixed
- "/r" no longer sends to an empty whisper target if the last told target is unavailable
- fixed replacements in instance chats
- messages to unknown numbered channels are now discarded
- right-click on the minimap button
## Version 1.1.6 - 2023-01-18
### Changed
- bumped version for latest WotLK Classic patch
### Fixed
- updated Ace3.0 libraries for latest WotLK Classic patch
## Version 1.1.5 - 2022-12-04 ## Version 1.1.5 - 2022-12-04
### Fixed ### Fixed
- updated Ace3 libraries for Dragonflight - updated Ace3 libraries for Dragonflight
+5 -3
View File
@@ -2,7 +2,7 @@
Grichelde - Text Replacer Grichelde - Text Replacer
Copyright 2020 Teilzeit-Jedi <tj@teilzeit-jedi.de> Copyright 2020 - 2026 Teilzeit-Jedi <tj@teilzeit-jedi.de>
This addon is distributed in the hope that it will be useful, This addon is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,6 +20,7 @@ local _G = _G
-- initialize addon -- initialize addon
local Grichelde = LibStub("AceAddon-3.0"):NewAddon(AddonTable, AddonName, "AceConsole-3.0", "AceEvent-3.0", "AceHook-3.0") local Grichelde = LibStub("AceAddon-3.0"):NewAddon(AddonTable, AddonName, "AceConsole-3.0", "AceEvent-3.0", "AceHook-3.0")
local GetAddOnMetadata = (_G.C_AddOns and _G.C_AddOns.GetAddOnMetadata) or _G.GetAddOnMetadata
Grichelde.version = GetAddOnMetadata(AddonName, "Version") Grichelde.version = GetAddOnMetadata(AddonName, "Version")
Grichelde.build = GetAddOnMetadata(AddonName, "X-Build") or "Development" Grichelde.build = GetAddOnMetadata(AddonName, "X-Build") or "Development"
--Grichelde.era = _G.WOW_PROJECT_ID == _G.WOW_PROJECT_CLASSIC --Grichelde.era = _G.WOW_PROJECT_ID == _G.WOW_PROJECT_CLASSIC
@@ -40,7 +41,7 @@ end
function Grichelde:OnEnable() function Grichelde:OnEnable()
-- Hook in before message is sent to replace all character occurrences where replacements have been defined in the options -- Hook in before message is sent to replace all character occurrences where replacements have been defined in the options
self:RawHook("SendChatMessage", true) self:HookSendChatMessage()
self.options, self.dialog = self:SetupOptions() self.options, self.dialog = self:SetupOptions()
self.ldb, self.icon = self:MinimapButton() self.ldb, self.icon = self:MinimapButton()
@@ -56,7 +57,8 @@ function Grichelde:OnEnable()
end end
function Grichelde:OnDisable() function Grichelde:OnDisable()
self:Unhook("SendChatMessage") self:UnhookAll()
self.originalSend = nil
self:CloseOptions() self:CloseOptions()
self:HideMinimapButton() self:HideMinimapButton()
self:UnregisterChatCommand("grichelde") self:UnregisterChatCommand("grichelde")
+8 -7
View File
@@ -1,20 +1,18 @@
## Interface: 100002 ## Interface: 120105, 16001, 11509, 20506, 38002, 50504
## Title: Grichelde ## Title: Grichelde
## Notes: Replaces characters of your chat input line before sending. ## Notes: Replaces characters of your chat input line before sending.
## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile vor dem Versenden. ## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile vor dem Versenden.
## Version: 1.1.5 ## Version: 1.1.7
## Author: Teilzeit-Jedi ## Author: Teilzeit-Jedi
## eMail: tj@teilzeit-jedi.de ## eMail: tj@teilzeit-jedi.de
## AllowLoadGameType: standard, classic, camelot, forever
## X-Build: Retail
## X-Compatible: 11403
## X-Compatible: 30400
## X-Curse-Project-ID: 385480 ## X-Curse-Project-ID: 385480
## X-License: GPLv3 ## X-License: GPLv3
## X-Category: Chat/Communication ## X-Category: Chat/Communication
## X-Credits: Teilzeit-Jedi ## X-Website: https://www.curseforge.com/wow/addons/grichelde
## X-Maintainer: Teilzeit-Jedi
## X-Embeds: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon ## X-Embeds: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon
## OptionalDeps: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon ## OptionalDeps: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon
@@ -45,3 +43,6 @@ GricheldeUpgrade.lua
GricheldeOptions.lua GricheldeOptions.lua
GricheldeMinimap.lua GricheldeMinimap.lua
GricheldeChat.lua GricheldeChat.lua
#@do-not-package@
GricheldeTest.lua
#@end-do-not-package@
+105 -17
View File
@@ -1,9 +1,9 @@
-- import addon read namespace from global env -- import addon read namespace from global env
local _G = _G local _G = _G or getfenv()
local Grichelde = _G.Grichelde or {} local Grichelde = _G.Grichelde or {}
local IsAddOnLoaded, assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tFilter, tInsert, tIsEmpty, find, sub, gsub, getNextCharUtf8, isUtf8MultiByte, getUtf8Sequence, isUpper, isLower, toUpper, toLower, bytes2Char, trim, length, lengthUtf8 local assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tFilter, tInsert, tIsEmpty, tSize, find, sub, gsub, getNextCharUtf8, isUtf8MultiByte, getUtf8Sequence, isUpper, isLower, toUpper, toLower, bytes2Char, trim, length, lengthUtf8
= Grichelde.F.IsAddOnLoaded, Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tFilter, Grichelde.F.tInsert, Grichelde.F.tIsEmpty, = Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tFilter, Grichelde.F.tInsert, Grichelde.F.tIsEmpty, Grichelde.F.tSize,
Grichelde.F.find, Grichelde.F.sub, Grichelde.F.gsub, Grichelde.F.getNextCharUtf8, Grichelde.F.isUtf8MultiByte, Grichelde.F.getUtf8Sequence, Grichelde.F.isUpper, Grichelde.F.isLower, Grichelde.F.toUpper, Grichelde.F.toLower, Grichelde.F.bytes2Char, Grichelde.F.trim, Grichelde.F.length, Grichelde.F.lengthUtf8 Grichelde.F.find, Grichelde.F.sub, Grichelde.F.gsub, Grichelde.F.getNextCharUtf8, Grichelde.F.isUtf8MultiByte, Grichelde.F.getUtf8Sequence, Grichelde.F.isUpper, Grichelde.F.isLower, Grichelde.F.toUpper, Grichelde.F.toLower, Grichelde.F.bytes2Char, Grichelde.F.trim, Grichelde.F.length, Grichelde.F.lengthUtf8
--- Splits a long text in longest possible chunks of <= 255 length, split at last available space --- Splits a long text in longest possible chunks of <= 255 length, split at last available space
@@ -142,13 +142,13 @@ end
function Grichelde:SendChunkifiedChatMessage(message, ...) function Grichelde:SendChunkifiedChatMessage(message, ...)
if (length(message) > 255) then if (length(message) > 255) then
local chunks = self:SplitText(message) local chunks = self:SplitText(message)
self:DebugPrint("SendChunkifiedChatMessage : #chunks:", #chunks) self:DebugPrint("SendChunkifiedChatMessage : #chunks:", tSize(chunks))
for _, chunk in ipairs(chunks) do for _, chunk in ipairs(chunks) do
self.hooks["SendChatMessage"](chunk, ...); self:SendOriginal(chunk, ...)
end end
else else
self.hooks["SendChatMessage"](message, ...); self:SendOriginal(message, ...)
end end
end end
@@ -206,6 +206,15 @@ function Grichelde:ReplaceCharacters(text, replName, replTable, consolidate, rep
p, patRest = getNextCharUtf8(patRest) p, patRest = getNextCharUtf8(patRest)
end end
ciPattern = ciPattern .. "]" ciPattern = ciPattern .. "]"
elseif (isUtf8MultiByte(p)) then
-- a set like [Ää] would match single bytes, so only group the differing last byte
local upperP, lowerP = toUpper(p), toLower(p)
local lead = sub(p, 1, -2)
if (upperP ~= lowerP) and (sub(upperP, 1, -2) == lead) and (sub(lowerP, 1, -2) == lead) then
ciPattern = ciPattern .. lead .. "[" .. sub(upperP, -1) .. sub(lowerP, -1) .. "]"
else
ciPattern = ciPattern .. p
end
else else
ciPattern = ciPattern .. "[" .. convertToCaseInsensitivePatternGroup(p) .. "]" ciPattern = ciPattern .. "[" .. convertToCaseInsensitivePatternGroup(p) .. "]"
end end
@@ -218,9 +227,10 @@ function Grichelde:ReplaceCharacters(text, replName, replTable, consolidate, rep
local function replaceCaptures(txt, replaceText, captures) local function replaceCaptures(txt, replaceText, captures)
local replText = replaceText local replText = replaceText
self:TracePrint("replaceCaptures : txt: %s, #captures: %d", txt, #captures) local n = tSize(captures)
self:TracePrint("replaceCaptures : txt: %s, #captures: %d", txt, n)
if (#captures > 0) then if (n > 0) then
for i, cap in ipairs(captures) do for i, cap in ipairs(captures) do
--self:TracePrint("replaceCaptures : i: %d, cap: %s", i, cap) --self:TracePrint("replaceCaptures : i: %d, cap: %s", i, cap)
if (cap == nil) then if (cap == nil) then
@@ -427,8 +437,9 @@ function Grichelde:ReplaceCharacters(text, replName, replTable, consolidate, rep
end end
-- update previous consolidate markers -- update previous consolidate markers
local diff = lengthUtf8(replText) - lengthUtf8(match) -- positions are byte offsets, so the difference must be counted in bytes as well
self:TracePrint("ReplaceCharacters : diff = %d - %d", lengthUtf8(replText), lengthUtf8(match)) local diff = length(replText) - length(match)
self:TracePrint("ReplaceCharacters : diff = %d - %d", length(replText), length(match))
for key, posList in pairs(consolidate) do for key, posList in pairs(consolidate) do
if (key ~= replName) then if (key ~= replName) then
for i, pc in ipairs(posList) do for i, pc in ipairs(posList) do
@@ -875,7 +886,7 @@ function Grichelde:CheckAndExtractMessageTypeTarget(message)
local type = tFilter(self.SUPPORTED_CHAT_COMMANDS, local type = tFilter(self.SUPPORTED_CHAT_COMMANDS,
function(_, k, _) return chatCmd == k end function(_, k, _) return chatCmd == k end
) )
assert(#type < 2) assert(tSize(type) < 2)
if (not tIsEmpty(type)) then if (not tIsEmpty(type)) then
self:DebugPrint("CheckAndExtractMessageTypeTarget : determined type: %s", type[1]) self:DebugPrint("CheckAndExtractMessageTypeTarget : determined type: %s", type[1])
@@ -885,8 +896,18 @@ function Grichelde:CheckAndExtractMessageTypeTarget(message)
-- special reply handling -- special reply handling
if ("/r" == chatCmd) or ("/reply" == chatCmd) then if ("/r" == chatCmd) or ("/reply" == chatCmd) then
-- reuse last type and target if possible -- reuse last type and target if possible
local lastTold, lastToldType = ChatEdit_GetLastToldTarget() local getLastToldTarget = (_G.ChatFrameUtil and _G.ChatFrameUtil.GetLastToldTarget) or _G.ChatEdit_GetLastToldTarget
local lastTold, lastToldType
if (getLastToldTarget ~= nil) then
lastTold, lastToldType = getLastToldTarget()
end
self:DebugPrint("CheckAndExtractMessageTypeTarget : lastTell, lastTellType =", lastTold, lastToldType) self:DebugPrint("CheckAndExtractMessageTypeTarget : lastTell, lastTellType =", lastTold, lastToldType)
if (nilOrEmpty(lastTold)) then
self:ErrorPrint(self.L.Error_InvalidWhisperTarget)
-- dont send text at all
return nil
end
return targetAndText, lastToldType or "WHISPER", lastTold return targetAndText, lastToldType or "WHISPER", lastTold
elseif ("/tt" == chatCmd) then elseif ("/tt" == chatCmd) then
-- determine target from game world selection -- determine target from game world selection
@@ -930,7 +951,7 @@ function Grichelde:CheckAndExtractMessageTypeTarget(message)
local _, _, channelNumber = find(chatCmd, "^/(%d+)") local _, _, channelNumber = find(chatCmd, "^/(%d+)")
if (channelNumber ~= nil) then if (channelNumber ~= nil) then
local channelId = GetChannelName(channelNumber) local channelId = GetChannelName(channelNumber)
if (channelId ~= nil) then if (channelId ~= nil) and (channelId > 0) then
return targetAndText, "CHANNEL", channelId return targetAndText, "CHANNEL", channelId
end end
end end
@@ -949,8 +970,50 @@ function Grichelde:CheckAndExtractMessageTypeTarget(message)
end end
end end
--- Hooks C_ChatInfo.SendChatMessage (Retail) and the global SendChatMessage (Classic, deprecated alias on Retail).
--- The original C_ChatInfo function is preferred for sending.
function Grichelde:HookSendChatMessage()
local chatInfo = _G.C_ChatInfo
if (chatInfo ~= nil) and (chatInfo.SendChatMessage ~= nil) then
self:RawHook(chatInfo, "SendChatMessage", "SendChatMessage", true)
self.originalSend = self.hooks[chatInfo]["SendChatMessage"]
end
if (_G.SendChatMessage ~= nil) then
self:RawHook("SendChatMessage", true)
self.originalSend = self.originalSend or self.hooks["SendChatMessage"]
end
end
--- Sends a message with the original (unhooked) send function.
function Grichelde:SendOriginal(...)
return self.originalSend(...)
end
--- Midnight blocks chat modifications by addons during instance encounters.
--- Prints a notice once per lockdown.
-- @return boolean
function Grichelde:IsChatLockedDown()
local chatInfo = _G.C_ChatInfo
if (chatInfo == nil) or (chatInfo.InChatMessagingLockdown == nil) then
return false
end
if (chatInfo.InChatMessagingLockdown()) then
if (not self.lockdownNoticeShown) then
self.lockdownNoticeShown = true
self:PrefixedPrint(self.L.Chat_Lockdown_Notice)
end
return true
end
self.lockdownNoticeShown = false
return false
end
function Grichelde:CleanseMessage(message) function Grichelde:CleanseMessage(message)
local text = message or "" local text = message or ""
local IsAddOnLoaded = (_G.C_AddOns and _G.C_AddOns.IsAddOnLoaded) or _G.IsAddOnLoaded
if (IsAddOnLoaded("Misspelled")) then if (IsAddOnLoaded("Misspelled")) then
self:DebugPrint("Misspelled detected: cleansing message") self:DebugPrint("Misspelled detected: cleansing message")
text = _G.Misspelled:RemoveHighlighting(message) text = _G.Misspelled:RemoveHighlighting(message)
@@ -970,7 +1033,12 @@ function Grichelde:SendChatMessageOverride(message, ...)
local msg, type, chan = self:CheckAndExtractMessageTypeTarget(cleasendText) local msg, type, chan = self:CheckAndExtractMessageTypeTarget(cleasendText)
if (msg ~= nil) then if (msg ~= nil) then
msg = self:ReplaceText(msg) if (not self:IsChatLockedDown()) then
msg = self:ReplaceText(msg)
else
-- do not modify message in any way during encounters
-- msg = msg .. self.L.Chat_Lockdown_Suffix
end
if (type ~= nil) then if (type ~= nil) then
self:SendChunkifiedChatMessage(msg, type, fallbackLang, chan, ...) self:SendChunkifiedChatMessage(msg, type, fallbackLang, chan, ...)
@@ -988,19 +1056,39 @@ end
-- @param language string -- @param language string
-- @param channel string -- @param channel string
function Grichelde:SendChatMessage(message, type, ...) function Grichelde:SendChatMessage(message, type, ...)
if (self.isReplacing) then
-- re-entered through the other hooked send function, text is already replaced
self:DebugPrint("SendChatMessage : already replacing")
self:SendOriginal(message, type, ...)
return
end
self.isReplacing = true
-- always reset the guard, even if replacing fails
local ok, err = pcall(self.ReplaceAndSendChatMessage, self, message, type, ...)
self.isReplacing = false
if (not ok) then
error(err, 0)
end
end
function Grichelde:ReplaceAndSendChatMessage(message, type, ...)
if (not self.db.profile.enabled) then if (not self.db.profile.enabled) then
self:DebugPrint("SendChatMessage : disabled") self:DebugPrint("SendChatMessage : disabled")
self.hooks["SendChatMessage"](message, type, ...); self:SendOriginal(message, type, ...)
elseif (nilOrEmpty(message)) then elseif (nilOrEmpty(message)) then
self:DebugPrint("SendChatMessage : no text") self:DebugPrint("SendChatMessage : no text")
self.hooks["SendChatMessage"](message, type, ...); self:SendOriginal(message, type, ...)
elseif (self:IsChatLockedDown()) then
self:DebugPrint("SendChatMessage : chat lockdown")
self:SendOriginal(message, type, ...)
else else
local cleasendText = self:CleanseMessage(message) local cleasendText = self:CleanseMessage(message)
if (self:CheckReplacementAllowed(cleasendText, type)) then if (self:CheckReplacementAllowed(cleasendText, type)) then
cleasendText = self:ReplaceText(cleasendText) cleasendText = self:ReplaceText(cleasendText)
self:SendChunkifiedChatMessage(cleasendText, type, ...) self:SendChunkifiedChatMessage(cleasendText, type, ...)
else else
self.hooks["SendChatMessage"](message, type, ...); self:SendOriginal(message, type, ...)
end end
end end
end end
+138 -17
View File
@@ -1,5 +1,5 @@
-- read namespace from global env -- read namespace from global env
local _G = _G local _G = _G or getfenv()
local Grichelde = _G.Grichelde or {} local Grichelde = _G.Grichelde or {}
-- constants and upvalues -- constants and upvalues
@@ -106,17 +106,17 @@ Grichelde.SUPPORTED_CHAT_COMMANDS = {
} }
Grichelde.BLIZZ_TYPE_TO_OPTIONS = { Grichelde.BLIZZ_TYPE_TO_OPTIONS = {
["SAY"] = "say", ["SAY"] = "say",
["EMOTE"] = "emote", ["EMOTE"] = "emote",
["YELL"] = "yell", ["YELL"] = "yell",
["PARTY"] = "party", ["PARTY"] = "party",
["GUILD"] = "guild", ["GUILD"] = "guild",
["OFFICER"] = "officer", ["OFFICER"] = "officer",
["RAID"] = "raid", ["RAID"] = "raid",
["RAID_WARNING"] = "raidWarning", ["RAID_WARNING"] = "raidWarning",
["INSTANCE"] = "instance", ["INSTANCE_CHAT"] = "instance",
["BATTLEGROUND"] = "battleground", ["BATTLEGROUND"] = "battleground",
["WHISPER"] = "whisper", ["WHISPER"] = "whisper",
} }
-- do not replace these patterns -- do not replace these patterns
@@ -168,7 +168,7 @@ Grichelde.IGNORE_PATTERNS = {
} }
local function nilOrEmpty(s) local function nilOrEmpty(s)
return s == nil or s:trim() == "" return s == nil or Grichelde.F.trim(s) == ""
end end
local function spairs(tbl, orderFunc) local function spairs(tbl, orderFunc)
@@ -287,6 +287,115 @@ local function getNextCharUtf8(word)
end end
end end
local function isUtf8MultiByte(word)
return Grichelde.F.length(word) ~= Grichelde.F.lengthUtf8(word)
end
local function getUtf8Sequence(word)
if ((word == nil) or (Grichelde.F.type(word) ~= "string") or (Grichelde.F.lengthUtf8(word) ~= 1)) then
return nil
end
--[[
You could use the following code snippet to iterate over UTF-8 sequences
(this will simply skip over most invalid codes):
for uchar in string.gmatch(ustring, "([%z\1-\127\194-\244][\128-\191]*)") do
...
end
]]--
local sequence = "%z"
local c1 = Grichelde.F.toByte(word, 1)
sequence = sequence .. "\\" .. c1
if (c1 > 0) and (c1 <= 127) then
-- UTF8-1
return sequence
end
local c2 = Grichelde.F.toByte(word, 2)
sequence = sequence .. "\\" .. c2
if (c1 >= 194) and (c1 <= 223) then
-- UTF8-2
return sequence
end
local c3 = Grichelde.F.toByte(word, 3)
sequence = sequence .. "\\" .. c3
if (c1 >= 224) and (c1 <= 239) then
-- UTF8-3
return sequence
end
local c4 = Grichelde.F.toByte(word, 4)
sequence = sequence .. "\\" .. c4
if (c1 >= 240) and (c1 <= 244) then
-- UTF8-4
return sequence
end
return nil
end
local function getUtf8Table(word)
if ((word == nil) or (Grichelde.F.type(word) ~= "string") or (Grichelde.F.lengthUtf8(word) ~= 1)) then
return nil
end
--[[
You could use the following code snippet to iterate over UTF-8 sequences
(this will simply skip over most invalid codes):
for uchar in string.gmatch(ustring, "([%z\1-\127\194-\244][\128-\191]*)") do
...
end
]]--
local tbl = {}
local c1 = Grichelde.F.toByte(word, 1)
Grichelde.F.tInsert(tbl, "%z\\" .. c1)
local c2 = Grichelde.F.toByte(word, 2)
if (c1 >= 194) and (c1 <= 223) then
-- UTF8-2
Grichelde.F.tInsert(tbl, "\\" .. c2)
end
local c3 = Grichelde.F.toByte(word, 3)
if (c1 >= 224) and (c1 <= 239) then
-- UTF8-3
Grichelde.F.tInsert(tbl, "\\" .. c3)
end
local c4 = Grichelde.F.toByte(word, 4)
if (c1 >= 240) and (c1 <= 244) then
-- UTF8-4
Grichelde.F.tInsert(tbl, "\\" .. c4)
end
return tbl
end
--- handles UTF-8 characters like äöü (except ß, ÿ, × and ÷)
local function toUpper(word)
return (Grichelde.F.gsub(_G.strupper(word), "\195([\160-\190])", function(c)
if (c ~= "\183") then
return "\195" .. Grichelde.F.bytes2Char(Grichelde.F.toByte(c) - 32)
end
end))
end
--- handles UTF-8 characters like äöü (except ß, ÿ, × and ÷)
local function toLower(word)
return (Grichelde.F.gsub(_G.strlower(word), "\195([\128-\158])", function(c)
if (c ~= "\151") then
return "\195" .. Grichelde.F.bytes2Char(Grichelde.F.toByte(c) + 32)
end
end))
end
local function isLetter(word) local function isLetter(word)
local char = Grichelde.F.getNextCharUtf8(word) local char = Grichelde.F.getNextCharUtf8(word)
return (char ~= nil) and (Grichelde.F.toUpper(char) ~= Grichelde.F.toLower(char)) return (char ~= nil) and (Grichelde.F.toUpper(char) ~= Grichelde.F.toLower(char))
@@ -348,6 +457,15 @@ local function capitalize(word)
end end
end end
local function trim(s)
if ((s == nil) or (Grichelde.F.type(s) ~= "string")) then
return nil
end
local n = Grichelde.F.find(s, "%S")
return n and Grichelde.F.match(s, ".*%S", n) or ""
end
local function color(colour, text) local function color(colour, text)
return colour .. text .. Grichelde.COLOR_CODES.CLOSE return colour .. text .. Grichelde.COLOR_CODES.CLOSE
end end
@@ -386,7 +504,6 @@ end
-- faster function lookups by mapping to local refs -- faster function lookups by mapping to local refs
Grichelde.F = { Grichelde.F = {
IsAddOnLoaded = _G.IsAddOnLoaded,
assert = _G.assert, assert = _G.assert,
type = _G.type, type = _G.type,
print = _G.print, print = _G.print,
@@ -415,9 +532,12 @@ Grichelde.F = {
gmatch = _G.string.gmatch, gmatch = _G.string.gmatch,
join = _G.strjoin, join = _G.strjoin,
split = _G.strsplit, split = _G.strsplit,
toUpper = _G.strupper, toUpper = toUpper,
toLower = _G.strlower, toLower = toLower,
getNextCharUtf8 = getNextCharUtf8, getNextCharUtf8 = getNextCharUtf8,
isUtf8MultiByte = isUtf8MultiByte,
getUtf8Sequence = getUtf8Sequence,
getUtf8Table = getUtf8Table,
isLetter = isLetter, isLetter = isLetter,
isNumber = isNumber, isNumber = isNumber,
isUpper = isUpper, isUpper = isUpper,
@@ -437,7 +557,8 @@ Grichelde.F = {
bytes2Char = _G.string.char, bytes2Char = _G.string.char,
format = _G.string.format, format = _G.string.format,
rep = _G.string.rep, rep = _G.string.rep,
trim = _G.strtrim, -- trim = _G.strtrim,
trim = trim,
length = _G.string.len, length = _G.string.len,
lengthUtf8 = _G.strlenutf8, lengthUtf8 = _G.strlenutf8,
toString = _G.tostring, toString = _G.tostring,
+11 -9
View File
@@ -1,9 +1,9 @@
-- read namespace from global env -- read namespace from global env
local _G = _G local _G = _G or getfenv()
local Grichelde = _G.Grichelde or {} local Grichelde = _G.Grichelde or {}
local pairs, tInsert, tClone, unpack, join, toString local pairs, tInsert, tClone, tSize, unpack, join, toString
= Grichelde.F.pairs, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.unpack, Grichelde.F.join, Grichelde.F.toString = Grichelde.F.pairs, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.tSize, Grichelde.F.unpack, Grichelde.F.join, Grichelde.F.toString
function Grichelde.getDefaultConfig() function Grichelde.getDefaultConfig()
return { return {
@@ -84,38 +84,40 @@ end
function Grichelde:SyncToDatabase(info, val) function Grichelde:SyncToDatabase(info, val)
self:TracePrint("SyncToDatabase : info") self:TracePrint("SyncToDatabase : info")
for i = 0, #info do local n = #info
for i = 0, n do
self:TracePrint("%d = %s", i, info[i]) self:TracePrint("%d = %s", i, info[i])
end end
local option = self.db.profile local option = self.db.profile
local path = 1 local path = 1
while (path < #info) do while (path < n) do
if (info[path] ~= "mappings") then if (info[path] ~= "mappings") then
option = option[info[path]] option = option[info[path]]
end end
path = path + 1 path = path + 1
end end
local optionPath = join(".", unpack(info, 1, #info)) local optionPath = join(".", unpack(info, 1, n))
self:DebugPrint("change option \"%s\" from %s to %s", optionPath, toString(option[info[path]]), toString(val)) self:DebugPrint("change option \"%s\" from %s to %s", optionPath, toString(option[info[path]]), toString(val))
option[info[path]] = val option[info[path]] = val
end end
function Grichelde:ReadFromDatabase(info) function Grichelde:ReadFromDatabase(info)
self:TracePrint("ReadFromDatabase : info") self:TracePrint("ReadFromDatabase : info")
for i = 0, #info do local n = #info
for i = 0, n do
self:TracePrint("%d = %s", i, info[i]) self:TracePrint("%d = %s", i, info[i])
end end
local option = self.db.profile local option = self.db.profile
local path = 1 local path = 1
while (path <= #info) do while (path <= n) do
if (info[path] ~= "mappings") then if (info[path] ~= "mappings") then
option = option[info[path]] option = option[info[path]]
end end
path = path + 1 path = path + 1
end end
local optionPath = join(".", unpack(info, 1, #info)) local optionPath = join(".", unpack(info, 1, n))
self:DebugPrint("read option \"%s\": %s", optionPath, toString(option)) self:DebugPrint("read option \"%s\": %s", optionPath, toString(option))
return option return option
end end
+3 -4
View File
@@ -1,9 +1,8 @@
-- read namespace from global env -- read namespace from global env
local _G = _G local _G = _G or getfenv()
local Grichelde = _G.Grichelde or {} local Grichelde = _G.Grichelde or {}
local cGreen, cRed local cGreen, cRed = Grichelde.F.cGreen, Grichelde.F.cRed
= Grichelde.F.cGreen, Grichelde.F.cRed
--- add Minimap button --- add Minimap button
@@ -49,7 +48,7 @@ function Grichelde:MinimapButton()
icon = "Interface\\Icons\\Spell_Holy_Silence", icon = "Interface\\Icons\\Spell_Holy_Silence",
--icon = ([[Interface\Addons\%s\%s]]):format(self.name, self.name), --icon = ([[Interface\Addons\%s\%s]]):format(self.name, self.name),
OnClick = clickHandler, OnClick = clickHandler,
OnRightClick = function() self:ShowMappings() end, OnRightClick = function() self:ToogleMappings() end,
OnTooltipShow = updateTooltip, OnTooltipShow = updateTooltip,
iconR = darkened, iconR = darkened,
iconG = darkened, iconG = darkened,
+9 -8
View File
@@ -1,9 +1,9 @@
-- read namespace from global env -- read namespace from global env
local _G = _G local _G = _G or getfenv()
local Grichelde = _G.Grichelde or {} local Grichelde = _G.Grichelde or {}
local assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tInsert, tClone, tWipe, find, match, cPrefix, cGray, cGreen, cOrange, cRed, format, toString, toNumber local assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tInsert, tClone, tSize, tWipe, find, match, cPrefix, cGray, cGreen, cOrange, cRed, format, toString, toNumber
= Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.tWipe, Grichelde.F.find, Grichelde.F.match, Grichelde.F.cPrefix, Grichelde.F.cGray, Grichelde.F.cGreen, Grichelde.F.cOrange, Grichelde.F.cRed, Grichelde.F.format, Grichelde.F.toString, Grichelde.F.toNumber = Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tInsert, Grichelde.F.tClone, Grichelde.F.tSize, Grichelde.F.tWipe, Grichelde.F.find, Grichelde.F.match, Grichelde.F.cPrefix, Grichelde.F.cGray, Grichelde.F.cGreen, Grichelde.F.cOrange, Grichelde.F.cRed, Grichelde.F.format, Grichelde.F.toString, Grichelde.F.toNumber
local selectedExample = 1 local selectedExample = 1
@@ -416,7 +416,6 @@ function Grichelde:SetupOptions()
LibStub("AceConfig-3.0"):RegisterOptionsTable(self.name, options) LibStub("AceConfig-3.0"):RegisterOptionsTable(self.name, options)
local dialog = LibStub("AceConfigDialog-3.0") local dialog = LibStub("AceConfigDialog-3.0")
dialog:AddToBlizOptions(self.name, self.L.AddonName) dialog:AddToBlizOptions(self.name, self.L.AddonName)
return options, dialog return options, dialog
end end
@@ -465,8 +464,9 @@ function Grichelde:RefreshProfiles(event, _, profileName)
end end
function Grichelde:ToggleOptions() function Grichelde:ToggleOptions()
self:DebugPrint("ToggleOptions : options open: ", not not self.dialog.OpenFrames[self.name]) local isOpen = (self.dialog ~= nil) and (self.dialog.OpenFrames[self.name] ~= nil)
if (self.dialog ~= nil) and (self.dialog.OpenFrames[self.name] ~= nil) then self:DebugPrint("ToggleOptions : options open: ", isOpen)
if (isOpen) then
self:CloseOptions() self:CloseOptions()
else else
self:OpenOptions() self:OpenOptions()
@@ -559,7 +559,7 @@ end
function Grichelde:ExtractExampleCodes(num) function Grichelde:ExtractExampleCodes(num)
self:TracePrint("ExtractExampleCodes : number is: %d", num) self:TracePrint("ExtractExampleCodes : number is: %d", num)
if (self.L.Options_Help_Examples[num] == nil) or (#self.L.Options_Help_Examples < num) then if (self.L.Options_Help_Examples[num] == nil) or (tSize(self.L.Options_Help_Examples) < num) then
self:DebugPrint("ExtractExampleCodes : invalid number: %d", num) self:DebugPrint("ExtractExampleCodes : invalid number: %d", num)
return self.L.Options_Help_Examples_Text return self.L.Options_Help_Examples_Text
end end
@@ -581,8 +581,9 @@ end
function Grichelde:ImportExample(num) function Grichelde:ImportExample(num)
self:TracePrint("ImportExample : number is: %d", num) self:TracePrint("ImportExample : number is: %d", num)
if (self.L.Options_Help_Examples[num] == nil) or (#self.L.Options_Help_Examples < num) then if (self.L.Options_Help_Examples[num] == nil) or (tSize(self.L.Options_Help_Examples) < num) then
self:DebugPrint("ImportExample : invalid number: %d", num) self:DebugPrint("ImportExample : invalid number: %d", num)
return
end end
local profileName = self.L.Options_Help_Examples[num].name local profileName = self.L.Options_Help_Examples[num].name
+52 -1
View File
@@ -1,5 +1,5 @@
-- import addon read namespace from global env -- import addon read namespace from global env
local _G = _G local _G = _G or getfenv()
local Grichelde = _G.Grichelde or {} local Grichelde = _G.Grichelde or {}
local find, pairs, tSize, cRed, cGreen = Grichelde.F.find, Grichelde.F.pairs, Grichelde.F.tSize, Grichelde.F.cRed, Grichelde.F.cGreen local find, pairs, tSize, cRed, cGreen = Grichelde.F.find, Grichelde.F.pairs, Grichelde.F.tSize, Grichelde.F.cRed, Grichelde.F.cGreen
@@ -776,6 +776,57 @@ function Grichelde:RunTests()
ok = ok + o ok = ok + o
all = all + a all = all + a
o, a = test(
"umlauts",
{
replacement_10 = {
order = 10,
searchText = "ä",
replaceText = "ae",
exactCase = false,
consolidate = false,
matchWhen = 2,
stopOnMatch = false,
},
replacement_11 = {
order = 11,
searchText = "ö",
replaceText = "oe",
exactCase = false,
consolidate = false,
matchWhen = 2,
stopOnMatch = false,
},
replacement_12 = {
order = 12,
searchText = "ü",
replaceText = "ue",
exactCase = false,
consolidate = true,
matchWhen = 2,
stopOnMatch = false,
},
replacement_13 = {
order = 13,
searchText = "ß",
replaceText = "ss",
exactCase = false,
consolidate = false,
matchWhen = 2,
stopOnMatch = false,
},
},
{
["Hallä"] = "Hallae",
["Ätsch"] = "Aetsch",
["Hällöluü"] = "Haelloeluue",
["ÜöÄ"] = "UeoeAE",
["Ää"] = "Aeae",
}
)
ok = ok + o
all = all + a
if (ok == all) then if (ok == all) then
self:PrefixedPrint("All %d tests %s", all, cGreen("passed")) self:PrefixedPrint("All %d tests %s", all, cGreen("passed"))
else else
+1 -1
View File
@@ -1,5 +1,5 @@
-- read namespace from global env -- read namespace from global env
local _G = _G local _G = _G or getfenv()
local Grichelde = _G.Grichelde or {} local Grichelde = _G.Grichelde or {}
local pairs, tClone, find, sub, cGreen, cOrange, cRed, toNumber local pairs, tClone, find, sub, cGreen, cOrange, cRed, toNumber
+4 -4
View File
@@ -1,5 +1,5 @@
-- import addon read namespace from global env -- import addon read namespace from global env
local _G = _G local _G = _G or getfenv()
local Grichelde = _G.Grichelde or {} local Grichelde = _G.Grichelde or {}
local type, print, pairs, tSize, select, unpack, find, cGray, cDarkgray, cRed, cPrefix, format, rep, toString local type, print, pairs, tSize, select, unpack, find, cGray, cDarkgray, cRed, cPrefix, format, rep, toString
@@ -171,7 +171,7 @@ end
--- Print UI options to chat frame --- Print UI options to chat frame
function Grichelde:PrintOptions() function Grichelde:PrintOptions()
self:PrefixedPrint(cPrefix(self.L.Debug_Options)) self:PrefixedPrint(cPrefix(self.L.Debug_Options))
self:LogPrint(-1, function(...) self:LogPrint(function(...)
print(cPrefix(self.L.AddonName) .. ":", self:Format(...)) print(cPrefix(self.L.AddonName) .. ":", self:Format(...))
end, self.options.args.replacements.args) end, self.options.args.replacements.args)
end end
@@ -179,7 +179,7 @@ end
--- Print current DB profile --- Print current DB profile
function Grichelde:PrintProfile() function Grichelde:PrintProfile()
self:PrefixedPrint(cPrefix(self.L.Debug_Profile)) self:PrefixedPrint(cPrefix(self.L.Debug_Profile))
self:LogPrint(-1, function(...) self:LogPrint(function(...)
print(cPrefix(self.L.AddonName) .. ":", self:Format(...)) print(cPrefix(self.L.AddonName) .. ":", self:Format(...))
end, self.db.profile) end, self.db.profile)
end end
@@ -187,7 +187,7 @@ end
--- Print DB replacements to chat frame --- Print DB replacements to chat frame
function Grichelde:PrintMappings() function Grichelde:PrintMappings()
self:PrefixedPrint(cPrefix(self.L.Debug_Mappings)) self:PrefixedPrint(cPrefix(self.L.Debug_Mappings))
self:LogPrint(-1, function(...) self:LogPrint(function(...)
print(cPrefix(self.L.AddonName) .. ":", self:Format(...)) print(cPrefix(self.L.AddonName) .. ":", self:Format(...))
end, self.db.profile.replacements) end, self.db.profile.replacements)
end end
-47
View File
@@ -1,47 +0,0 @@
## Interface: 11403
## Title: Grichelde
## Notes: Replaces characters of your chat input line before sending.
## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile vor dem Versenden.
## Version: 1.1.5
## Author: Teilzeit-Jedi
## eMail: tj@teilzeit-jedi.de
## X-Build: Classic
## X-Compatible: 30400
## X-Compatible: 100002
## X-Curse-Project-ID: 385480
## X-License: GPLv3
## X-Category: Chat/Communication
## X-Credits: Teilzeit-Jedi
## X-Embeds: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon
## OptionalDeps: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon
## SavedVariables: GricheldeDB
Libs\LibStub\LibStub.lua
Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml
Libs\AceAddon-3.0\AceAddon-3.0.xml
Libs\AceLocale-3.0\AceLocale-3.0.xml
Libs\AceEvent-3.0\AceEvent-3.0.xml
Libs\AceHook-3.0\AceHook-3.0.xml
Libs\AceConsole-3.0\AceConsole-3.0.xml
Libs\AceDB-3.0\AceDB-3.0.xml
Libs\AceDBOptions-3.0\AceDBOptions-3.0.xml
Libs\AceGUI-3.0\AceGUI-3.0.xml
Libs\AceConfig-3.0\AceConfig-3.0.xml
Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua
Libs\LibDBIcon-1.0\LibDBIcon-1.0.lua
Grichelde.lua
GricheldeConstants.lua
localisation.xml
GricheldeUtils.lua
GricheldeDatabase.lua
GricheldeUpgrade.lua
GricheldeOptions.lua
GricheldeMinimap.lua
GricheldeChat.lua
-47
View File
@@ -1,47 +0,0 @@
## Interface: 30400
## Title: Grichelde
## Notes: Replaces characters of your chat input line before sending.
## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile vor dem Versenden.
## Version: 1.1.5
## Author: Teilzeit-Jedi
## eMail: tj@teilzeit-jedi.de
## X-Build: WotLK
## X-Compatible: 11403
## X-Compatible: 100002
## X-Curse-Project-ID: 385480
## X-License: GPLv3
## X-Category: Chat/Communication
## X-Credits: Teilzeit-Jedi
## X-Embeds: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon
## OptionalDeps: LibStub, CallbackHandler, Ace3, LibDataBroker, LibDBIcon
## SavedVariables: GricheldeDB
Libs\LibStub\LibStub.lua
Libs\CallbackHandler-1.0\CallbackHandler-1.0.xml
Libs\AceAddon-3.0\AceAddon-3.0.xml
Libs\AceLocale-3.0\AceLocale-3.0.xml
Libs\AceEvent-3.0\AceEvent-3.0.xml
Libs\AceHook-3.0\AceHook-3.0.xml
Libs\AceConsole-3.0\AceConsole-3.0.xml
Libs\AceDB-3.0\AceDB-3.0.xml
Libs\AceDBOptions-3.0\AceDBOptions-3.0.xml
Libs\AceGUI-3.0\AceGUI-3.0.xml
Libs\AceConfig-3.0\AceConfig-3.0.xml
Libs\LibDataBroker-1.1\LibDataBroker-1.1.lua
Libs\LibDBIcon-1.0\LibDBIcon-1.0.lua
Grichelde.lua
GricheldeConstants.lua
localisation.xml
GricheldeUtils.lua
GricheldeDatabase.lua
GricheldeUpgrade.lua
GricheldeOptions.lua
GricheldeMinimap.lua
GricheldeChat.lua
+1 -1
View File
@@ -27,7 +27,7 @@ if not AceConfig then return end
local pcall, error, type, pairs = pcall, error, type, pairs local pcall, error, type, pairs = pcall, error, type, pairs
-- ------------------------------------------------------------------- -- -------------------------------------------------------------------
-- :RegisterOptionsTable(appName, options, slashcmd, persist) -- :RegisterOptionsTable(appName, options, slashcmd)
-- --
-- - appName - (string) application name -- - appName - (string) application name
-- - options - table or function ref, see AceConfigRegistry -- - options - table or function ref, see AceConfigRegistry
@@ -7,7 +7,7 @@ local LibStub = LibStub
local gui = LibStub("AceGUI-3.0") local gui = LibStub("AceGUI-3.0")
local reg = LibStub("AceConfigRegistry-3.0") local reg = LibStub("AceConfigRegistry-3.0")
local MAJOR, MINOR = "AceConfigDialog-3.0", 85 local MAJOR, MINOR = "AceConfigDialog-3.0", 93
local AceConfigDialog, oldminor = LibStub:NewLibrary(MAJOR, MINOR) local AceConfigDialog, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigDialog then return end if not AceConfigDialog then return end
@@ -147,6 +147,7 @@ local stringIsLiteral = {
width = true, width = true,
image = true, image = true,
fontSize = true, fontSize = true,
tooltipHyperlink = true
} }
--Is Never a function or method --Is Never a function or method
@@ -501,6 +502,14 @@ local function OptionOnMouseOver(widget, event)
local tooltip = AceConfigDialog.tooltip local tooltip = AceConfigDialog.tooltip
tooltip:SetOwner(widget.frame, "ANCHOR_TOPRIGHT") tooltip:SetOwner(widget.frame, "ANCHOR_TOPRIGHT")
local tooltipHyperlink = GetOptionsMemberValue("tooltipHyperlink", opt, options, path, appName)
if tooltipHyperlink then
tooltip:SetHyperlink(tooltipHyperlink)
tooltip:Show()
return
end
local name = GetOptionsMemberValue("name", opt, options, path, appName) local name = GetOptionsMemberValue("name", opt, options, path, appName)
local desc = GetOptionsMemberValue("desc", opt, options, path, appName) local desc = GetOptionsMemberValue("desc", opt, options, path, appName)
local usage = GetOptionsMemberValue("usage", opt, options, path, appName) local usage = GetOptionsMemberValue("usage", opt, options, path, appName)
@@ -508,7 +517,7 @@ local function OptionOnMouseOver(widget, event)
if descStyle and descStyle ~= "tooltip" then return end if descStyle and descStyle ~= "tooltip" then return end
tooltip:SetText(name, 1, .82, 0, true) tooltip:SetText(name, 1, .82, 0, 1, true)
if opt.type == "multiselect" then if opt.type == "multiselect" then
tooltip:AddLine(user.text, 0.5, 0.5, 0.8, true) tooltip:AddLine(user.text, 0.5, 0.5, 0.8, true)
@@ -517,7 +526,7 @@ local function OptionOnMouseOver(widget, event)
tooltip:AddLine(desc, 1, 1, 1, true) tooltip:AddLine(desc, 1, 1, 1, true)
end end
if type(usage) == "string" then if type(usage) == "string" then
tooltip:AddLine("Usage: "..usage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true) tooltip:AddLine(usage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true)
end end
tooltip:Show() tooltip:Show()
@@ -535,25 +544,28 @@ local function GetFuncName(option)
end end
end end
do do
local InCombatLockdown = InCombatLockdown
local frame = AceConfigDialog.popup local frame = AceConfigDialog.popup
if not frame or oldminor < 81 then if not frame or oldminor < 93 then
frame = CreateFrame("Frame", nil, UIParent) frame = CreateFrame("Frame", nil, UIParent)
AceConfigDialog.popup = frame AceConfigDialog.popup = frame
frame:Hide() frame:Hide()
frame:SetPoint("CENTER", UIParent, "CENTER") frame:SetPoint("CENTER", UIParent, "CENTER")
frame:SetSize(320, 72) frame:SetSize(400, 72)
frame:EnableMouse(true) -- Do not allow click-through on the frame frame:EnableMouse(true) -- Do not allow click-through on the frame
frame:SetFrameStrata("TOOLTIP") frame:SetFrameStrata("TOOLTIP")
frame:SetFrameLevel(100) -- Lots of room to draw under it frame:SetFrameLevel(100) -- Lots of room to draw under it
frame:SetScript("OnKeyDown", function(self, key) frame:SetScript("OnKeyDown", function(self, key)
if key == "ESCAPE" then if key == "ESCAPE" then
self:SetPropagateKeyboardInput(false) if not InCombatLockdown() then
self:SetPropagateKeyboardInput(false)
end
if self.cancel:IsShown() then if self.cancel:IsShown() then
self.cancel:Click() self.cancel:Click()
else -- Showing a validation error else -- Showing a validation error
self:Hide() self:Hide()
end end
else elseif not InCombatLockdown() then
self:SetPropagateKeyboardInput(true) self:SetPropagateKeyboardInput(true)
end end
end) end)
@@ -564,7 +576,7 @@ do
frame:SetFixedFrameLevel(true) frame:SetFixedFrameLevel(true)
local text = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlight") local text = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
text:SetSize(290, 0) text:SetSize(370, 0)
text:SetPoint("TOP", 0, -16) text:SetPoint("TOP", 0, -16)
frame.text = text frame.text = text
@@ -596,11 +608,7 @@ local function confirmPopup(appName, rootframe, basepath, info, message, func, .
local frame = AceConfigDialog.popup local frame = AceConfigDialog.popup
frame:Show() frame:Show()
frame.text:SetText(message) frame.text:SetText(message)
-- From StaticPopup.lua local height = 70 + frame.text:GetHeight()
-- local height = 32 + text:GetHeight() + 2;
-- height = height + 6 + accept:GetHeight()
-- We add 32 + 2 + 6 + 21 (button height) == 61
local height = 61 + frame.text:GetHeight()
frame:SetHeight(height) frame:SetHeight(height)
frame.accept:ClearAllPoints() frame.accept:ClearAllPoints()
@@ -1071,6 +1079,11 @@ local function InjectInfo(control, options, option, path, rootframe, appName)
control:SetCallback("OnRelease", CleanUserData) control:SetCallback("OnRelease", CleanUserData)
control:SetCallback("OnLeave", OptionOnMouseLeave) control:SetCallback("OnLeave", OptionOnMouseLeave)
control:SetCallback("OnEnter", OptionOnMouseOver) control:SetCallback("OnEnter", OptionOnMouseOver)
-- forward custom arg data directly
if control.SetCustomData and option.arg then
safecall(control.SetCustomData, control, option.arg)
end
end end
local function CreateControl(userControlType, fallbackControlType) local function CreateControl(userControlType, fallbackControlType)
@@ -1424,12 +1437,15 @@ local function FeedOptions(appName, options,container,rootframe,path,group,inlin
if control then if control then
if control.width ~= "fill" then if control.width ~= "fill" then
local width = GetOptionsMemberValue("width",v,options,path,appName) local width = GetOptionsMemberValue("width",v,options,path,appName)
local relWidth = GetOptionsMemberValue("relWidth",v,options,path,appName)
if width == "double" then if width == "double" then
control:SetWidth(width_multiplier * 2) control:SetWidth(width_multiplier * 2)
elseif width == "half" then elseif width == "half" then
control:SetWidth(width_multiplier / 2) control:SetWidth(width_multiplier / 2)
elseif (type(width) == "number") then elseif (type(width) == "number") then
control:SetWidth(width_multiplier * width) control:SetWidth(width_multiplier * width)
elseif width == "relative" and relWidth then
control:SetRelativeWidth(relWidth)
elseif width == "full" then elseif width == "full" then
control.width = "fill" control.width = "fill"
else else
@@ -1494,7 +1510,7 @@ local function TreeOnButtonEnter(widget, event, uniquevalue, button)
tooltip:SetPoint("LEFT",button,"RIGHT") tooltip:SetPoint("LEFT",button,"RIGHT")
end end
tooltip:SetText(name, 1, .82, 0, true) tooltip:SetText(name, 1, .82, 0, 1, true)
if type(desc) == "string" then if type(desc) == "string" then
tooltip:AddLine(desc, 1, 1, 1, true) tooltip:AddLine(desc, 1, 1, 1, true)
@@ -1933,6 +1949,8 @@ else
AceConfigDialog.BlizOptions = AceConfigDialog.BlizOptions or {} AceConfigDialog.BlizOptions = AceConfigDialog.BlizOptions or {}
end end
AceConfigDialog.BlizOptionsIDMap = AceConfigDialog.BlizOptionsIDMap or {}
local function FeedToBlizPanel(widget, event) local function FeedToBlizPanel(widget, event)
local path = widget:GetUserData("path") local path = widget:GetUserData("path")
AceConfigDialog:Open(widget:GetUserData("appName"), widget, unpack(path or emptyTbl)) AceConfigDialog:Open(widget:GetUserData("appName"), widget, unpack(path or emptyTbl))
@@ -1954,16 +1972,17 @@ end
-- has to be a head-level note. -- has to be a head-level note.
-- --
-- This function returns a reference to the container frame registered with the Interface -- This function returns a reference to the container frame registered with the Interface
-- Options. You can use this reference to open the options with the API function -- Options, as well as the registered ID. You can use the ID to open the options with
-- `InterfaceOptionsFrame_OpenToCategory`. -- the API function `Settings.OpenToCategory`.
-- @param appName The application name as given to `:RegisterOptionsTable()` -- @param appName The application name as given to `:RegisterOptionsTable()`
-- @param name A descriptive name to display in the options tree (defaults to appName) -- @param name A descriptive name to display in the options tree (defaults to appName)
-- @param parent The parent to use in the interface options tree. -- @param parent The parent to use in the interface options tree.
-- @param ... The path in the options table to feed into the interface options panel. -- @param ... The path in the options table to feed into the interface options panel.
-- @return The reference to the frame registered into the Interface Options. -- @return The reference to the frame registered into the Interface Options.
-- @return The category ID to pass to Settings.OpenToCategory (or InterfaceOptionsFrame_OpenToCategory) -- @return The category ID to pass to Settings.OpenToCategory
function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...) function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
local BlizOptions = AceConfigDialog.BlizOptions local BlizOptions = AceConfigDialog.BlizOptions
local BlizOptionsIDMap = AceConfigDialog.BlizOptionsIDMap
local key = appName local key = appName
for n = 1, select("#", ...) do for n = 1, select("#", ...) do
@@ -1989,29 +2008,32 @@ function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
end end
group:SetCallback("OnShow", FeedToBlizPanel) group:SetCallback("OnShow", FeedToBlizPanel)
group:SetCallback("OnHide", ClearBlizPanel) group:SetCallback("OnHide", ClearBlizPanel)
if Settings and Settings.RegisterCanvasLayoutCategory then
local categoryName = name or appName
if parent then
local category = Settings.GetCategory(parent)
if not category then
error(("The parent category '%s' was not found"):format(parent), 2)
end
local subcategory = Settings.RegisterCanvasLayoutSubcategory(category, group.frame, categoryName)
-- force the generated ID to be used for subcategories, as these can have very simple names like "Profiles" local categoryName = name or appName
group:SetName(subcategory.ID, parent) if parent then
else local parentID = BlizOptionsIDMap[parent] or parent
local category = Settings.RegisterCanvasLayoutCategory(group.frame, categoryName) local category = Settings.GetCategory(parentID)
-- using appName here would be cleaner, but would not be 100% compatible if not category then
-- but for top-level categories it should be fine, as these are typically addon names error(("The parent category '%s' was not found"):format(parent), 2)
category.ID = categoryName
group:SetName(categoryName, parent)
Settings.RegisterAddOnCategory(category)
end end
local subcategory = Settings.RegisterCanvasLayoutSubcategory(category, group.frame, categoryName)
group:SetName(subcategory.ID, parentID)
else else
group:SetName(name or appName, parent) if BlizOptionsIDMap[categoryName] then
InterfaceOptions_AddCategory(group.frame) error(("%s has already been added to the Blizzard Options Window with the given name: %s"):format(appName, categoryName), 2)
end
local category = Settings.RegisterCanvasLayoutCategory(group.frame, categoryName)
if not (C_SettingsUtil and C_SettingsUtil.OpenSettingsPanel) then
-- override the ID so the name can be used in Settings.OpenToCategory
-- unfortunately with incoming API changes in 12.0 (and likely classic at some point) this override is no longer possible
category.ID = categoryName
end
group:SetName(category.ID)
BlizOptionsIDMap[categoryName] = category.ID
Settings.RegisterAddOnCategory(category)
end end
return group.frame, group.frame.name return group.frame, group.frame.name
else else
error(("%s has already been added to the Blizzard Options Window with the given path"):format(appName), 2) error(("%s has already been added to the Blizzard Options Window with the given path"):format(appName), 2)
@@ -11,7 +11,7 @@
-- @release $Id$ -- @release $Id$
local CallbackHandler = LibStub("CallbackHandler-1.0") local CallbackHandler = LibStub("CallbackHandler-1.0")
local MAJOR, MINOR = "AceConfigRegistry-3.0", 20 local MAJOR, MINOR = "AceConfigRegistry-3.0", 22
local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR) local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigRegistry then return end if not AceConfigRegistry then return end
@@ -83,6 +83,7 @@ local basekeys={
dialogHidden=optmethodbool, dialogHidden=optmethodbool,
dropdownHidden=optmethodbool, dropdownHidden=optmethodbool,
cmdHidden=optmethodbool, cmdHidden=optmethodbool,
tooltipHyperlink=optstringfunc,
icon=optstringnumberfunc, icon=optstringnumberfunc,
iconCoords=optmethodtable, iconCoords=optmethodtable,
handler=opttable, handler=opttable,
@@ -91,6 +92,7 @@ local basekeys={
func=optmethodfalse, func=optmethodfalse,
arg={["*"]=true}, arg={["*"]=true},
width=optstringnumber, width=optstringnumber,
relWidth=optnumber,
} }
local typedkeys={ local typedkeys={
+122 -14
View File
@@ -41,7 +41,7 @@
-- @class file -- @class file
-- @name AceDB-3.0.lua -- @name AceDB-3.0.lua
-- @release $Id$ -- @release $Id$
local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 27 local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 40
local AceDB = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR) local AceDB = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
if not AceDB then return end -- No upgrade needed if not AceDB then return end -- No upgrade needed
@@ -49,6 +49,7 @@ if not AceDB then return end -- No upgrade needed
-- Lua APIs -- Lua APIs
local type, pairs, next, error = type, pairs, next, error local type, pairs, next, error = type, pairs, next, error
local setmetatable, rawset, rawget = setmetatable, rawset, rawget local setmetatable, rawset, rawget = setmetatable, rawset, rawget
local strlenutf8 = strlenutf8
-- WoW APIs -- WoW APIs
local _G = _G local _G = _G
@@ -251,17 +252,43 @@ local preserve_keys = {
["children"] = true, ["children"] = true,
} }
local realmKey = GetRealmName()
local charKey = UnitName("player") .. " - " .. realmKey
local _, classKey = UnitClass("player")
local _, raceKey = UnitRace("player")
local factionKey = UnitFactionGroup("player") local factionKey = UnitFactionGroup("player")
local factionrealmKey = factionKey .. " - " .. realmKey
local localeKey = GetLocale():lower() local localeKey = GetLocale():lower()
local charKey, realmKey, classKey, raceKey, factionrealmKey, factionrealmregionKey
do
local _
_, classKey = UnitClass("player")
_, raceKey = UnitRace("player")
local regionTable = { "US", "KR", "EU", "TW", "CN" } if RegionalUniqueNamesEnabled and RegionalUniqueNamesEnabled() then
local regionKey = regionTable[GetCurrentRegion()] local isRP = C_GameRules.IsGameRuleActive(Enum.GameRule.RPRuleset)
local factionrealmregionKey = factionrealmKey .. " - " .. regionKey local isPVP = C_GameRules.IsGameRuleActive(Enum.GameRule.PvPRuleset)
if C_GameRules.IsGameRuleActive(Enum.GameRule.HardcoreRuleset) then
realmKey = "Hardcore"
elseif isRP and isPVP then
realmKey = "RP-PvP"
elseif isRP then
realmKey = "RP"
elseif isPVP then
realmKey = "PvP"
else
realmKey = "PvE"
end
local name, surname = UnitNameUnmodified("player")
charKey = name .. " " .. surname
else
realmKey = GetRealmName()
charKey = UnitNameUnmodified("player") .. " - " .. realmKey
end
local regionTable = { "US", "KR", "EU", "TW", "CN" }
local regionName = GetCurrentRegionName()
if regionName and regionName == "" then regionName = nil end -- PTR/Beta tends to be ""
local regionKey = regionTable[GetCurrentRegion()] or regionName or "TR"
factionrealmKey = factionKey .. " - " .. realmKey
factionrealmregionKey = factionrealmKey .. " - " .. regionKey
end
-- Actual database initialization function -- Actual database initialization function
local function initdb(sv, defaults, defaultProfile, olddb, parent) local function initdb(sv, defaults, defaultProfile, olddb, parent)
@@ -275,6 +302,18 @@ local function initdb(sv, defaults, defaultProfile, olddb, parent)
-- Make a container for profile keys -- Make a container for profile keys
if not sv.profileKeys then sv.profileKeys = {} end if not sv.profileKeys then sv.profileKeys = {} end
-- Validate any existing profile name
if sv.profileKeys[charKey] then
if type(sv.profileKeys[charKey]) ~= "string" then
sv.profileKeys[charKey] = defaultProfile or charKey
else
local profileNameLength = strlenutf8(sv.profileKeys[charKey])
if profileNameLength == 0 or profileNameLength > 50 or sv.profileKeys[charKey]:find("^ +$") then
sv.profileKeys[charKey] = defaultProfile or charKey
end
end
end
-- Try to get the profile selected from the char db -- Try to get the profile selected from the char db
profileKey = sv.profileKeys[charKey] or defaultProfile or charKey profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
@@ -360,7 +399,7 @@ local function logoutHandler(frame, event)
-- cleanup sections that are empty without defaults -- cleanup sections that are empty without defaults
local sv = rawget(db, "sv") local sv = rawget(db, "sv")
for section in pairs(db.keys) do for section in pairs(rawget(db, "keys")) do
if rawget(sv, section) then if rawget(sv, section) then
-- global is special, all other sections have sub-entrys -- global is special, all other sections have sub-entrys
-- also don't delete empty profiles on main dbs, only on namespaces -- also don't delete empty profiles on main dbs, only on namespaces
@@ -377,6 +416,26 @@ local function logoutHandler(frame, event)
end end
end end
end end
-- second pass after everything else is cleaned up to remove empty namespaces
-- can't be run in-loop above since there is no guaranteed order
for db in pairs(AceDB.db_registry) do
local sv = rawget(db, "sv")
local namespaces = rawget(sv, "namespaces")
if namespaces then
for name in pairs(namespaces) do
-- cleanout empty profiles table, if still present
if namespaces[name].profiles and not next(namespaces[name].profiles) then
namespaces[name].profiles = nil
end
-- remove entire namespace, if needed
if not next(namespaces[name]) then
namespaces[name] = nil
end
end
end
end
end end
end end
@@ -426,6 +485,11 @@ end
function DBObjectLib:SetProfile(name) function DBObjectLib:SetProfile(name)
if type(name) ~= "string" then if type(name) ~= "string" then
error(("Usage: AceDBObject:SetProfile(name): 'name' - string expected, got %q."):format(type(name)), 2) error(("Usage: AceDBObject:SetProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
else
local profileNameLength = strlenutf8(name)
if profileNameLength == 0 or profileNameLength > 50 or name:find("^ +$") then
error("Usage: AceDBObject:SetProfile(name): 'name' - string length must be between 1 and 50 characters.", 2)
end
end end
-- changing to the same profile, dont do anything -- changing to the same profile, dont do anything
@@ -525,6 +589,17 @@ function DBObjectLib:DeleteProfile(name, silent)
end end
end end
-- remove from unloaded namespaces
if self.sv.namespaces then
for nsname, data in pairs(self.sv.namespaces) do
if self.children and self.children[nsname] then
-- already a mapped namespace
elseif data.profiles then
data.profiles[name] = nil
end
end
end
-- switch all characters that use this profile back to the default -- switch all characters that use this profile back to the default
if self.sv.profileKeys then if self.sv.profileKeys then
for key, profile in pairs(self.sv.profileKeys) do for key, profile in pairs(self.sv.profileKeys) do
@@ -570,6 +645,20 @@ function DBObjectLib:CopyProfile(name, silent)
end end
end end
-- copy unloaded namespaces
if self.sv.namespaces then
for nsname, data in pairs(self.sv.namespaces) do
if self.children and self.children[nsname] then
-- already a mapped namespace
elseif data.profiles then
-- reset the current profile
data.profiles[self.keys.profile] = {}
-- copy data
copyTable(data.profiles[name], data.profiles[self.keys.profile])
end
end
end
-- Callback: OnProfileCopied, database, sourceProfileKey -- Callback: OnProfileCopied, database, sourceProfileKey
self.callbacks:Fire("OnProfileCopied", self, name) self.callbacks:Fire("OnProfileCopied", self, name)
end end
@@ -596,6 +685,18 @@ function DBObjectLib:ResetProfile(noChildren, noCallbacks)
end end
end end
-- reset unloaded namespaces
if self.sv.namespaces and not noChildren then
for nsname, data in pairs(self.sv.namespaces) do
if self.children and self.children[nsname] then
-- already a mapped namespace
elseif data.profiles then
-- reset the current profile
data.profiles[self.keys.profile] = nil
end
end
end
-- Callback: OnProfileReset, database -- Callback: OnProfileReset, database
if not noCallbacks then if not noCallbacks then
self.callbacks:Fire("OnProfileReset", self) self.callbacks:Fire("OnProfileReset", self)
@@ -606,8 +707,8 @@ end
-- profile. -- profile.
-- @param defaultProfile The profile name to use as the default -- @param defaultProfile The profile name to use as the default
function DBObjectLib:ResetDB(defaultProfile) function DBObjectLib:ResetDB(defaultProfile)
if defaultProfile and type(defaultProfile) ~= "string" then if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
error(("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected, got %q."):format(type(defaultProfile)), 2) error(("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or true expected, got %q."):format(type(defaultProfile)), 2)
end end
local sv = self.sv local sv = self.sv
@@ -720,8 +821,15 @@ function AceDB:New(tbl, defaults, defaultProfile)
error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected, got %q."):format(type(defaults)), 2) error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected, got %q."):format(type(defaults)), 2)
end end
if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then if defaultProfile then
error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected, got %q."):format(type(defaultProfile)), 2) if type(defaultProfile) == "string" then
local profileNameLength = strlenutf8(defaultProfile)
if profileNameLength == 0 or profileNameLength > 50 or defaultProfile:find("^ +$") then
error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string length must be between 1 and 50 characters.", 2)
end
elseif defaultProfile ~= true then
error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected, got %q."):format(type(defaultProfile)), 2)
end
end end
return initdb(tbl, defaults, defaultProfile) return initdb(tbl, defaults, defaultProfile)
+47 -24
View File
@@ -2,7 +2,7 @@
-- @class file -- @class file
-- @name AceDBOptions-3.0 -- @name AceDBOptions-3.0
-- @release $Id$ -- @release $Id$
local ACEDBO_MAJOR, ACEDBO_MINOR = "AceDBOptions-3.0", 15 local ACEDBO_MAJOR, ACEDBO_MINOR = "AceDBOptions-3.0", 17
local AceDBOptions = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR) local AceDBOptions = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR)
if not AceDBOptions then return end -- No upgrade needed if not AceDBOptions then return end -- No upgrade needed
@@ -33,6 +33,7 @@ local L = {
delete_desc = "Delete existing and unused profiles from the database to save space, and cleanup the SavedVariables file.", delete_desc = "Delete existing and unused profiles from the database to save space, and cleanup the SavedVariables file.",
delete_sub = "Deletes a profile from the database.", delete_sub = "Deletes a profile from the database.",
intro = "You can change the active database profile, so you can have different settings for every character.", intro = "You can change the active database profile, so you can have different settings for every character.",
name_too_long = "Profile names cannot be longer than 50 characters.",
new = "New", new = "New",
new_sub = "Create a new empty profile.", new_sub = "Create a new empty profile.",
profiles = "Profiles", profiles = "Profiles",
@@ -56,6 +57,7 @@ if LOCALE == "deDE" then
L["delete_desc"] = "Lösche vorhandene oder unbenutzte Profile aus der Datenbank, um Platz zu sparen und die SavedVariables-Datei 'sauber' zu halten." L["delete_desc"] = "Lösche vorhandene oder unbenutzte Profile aus der Datenbank, um Platz zu sparen und die SavedVariables-Datei 'sauber' zu halten."
L["delete_sub"] = "Löscht ein Profil aus der Datenbank." L["delete_sub"] = "Löscht ein Profil aus der Datenbank."
L["intro"] = "Hier kannst du das aktive Datenbankprofil ändern, damit du verschiedene Einstellungen für jeden Charakter erstellen kannst, wodurch eine sehr flexible Konfiguration möglich wird." L["intro"] = "Hier kannst du das aktive Datenbankprofil ändern, damit du verschiedene Einstellungen für jeden Charakter erstellen kannst, wodurch eine sehr flexible Konfiguration möglich wird."
L["name_too_long"] = "Profilnamen können nicht länger als 50 Zeichen sein."
L["new"] = "Neu" L["new"] = "Neu"
L["new_sub"] = "Ein neues Profil erstellen." L["new_sub"] = "Ein neues Profil erstellen."
L["profiles"] = "Profile" L["profiles"] = "Profile"
@@ -76,6 +78,7 @@ elseif LOCALE == "frFR" then
L["delete_desc"] = "Supprime les profils existants inutilisés de la base de données afin de gagner de la place et de nettoyer le fichier SavedVariables." L["delete_desc"] = "Supprime les profils existants inutilisés de la base de données afin de gagner de la place et de nettoyer le fichier SavedVariables."
L["delete_sub"] = "Supprime un profil de la base de données." L["delete_sub"] = "Supprime un profil de la base de données."
L["intro"] = "Vous pouvez changer le profil actuel afin d'avoir des paramètres différents pour chaque personnage, permettant ainsi d'avoir une configuration très flexible." L["intro"] = "Vous pouvez changer le profil actuel afin d'avoir des paramètres différents pour chaque personnage, permettant ainsi d'avoir une configuration très flexible."
L["name_too_long"] = "Les noms de profil ne peuvent pas dépasser 50 caractères."
L["new"] = "Nouveau" L["new"] = "Nouveau"
L["new_sub"] = "Créée un nouveau profil vierge." L["new_sub"] = "Créée un nouveau profil vierge."
L["profiles"] = "Profils" L["profiles"] = "Profils"
@@ -84,25 +87,26 @@ elseif LOCALE == "frFR" then
L["reset_desc"] = "Réinitialise le profil actuel au cas où votre configuration est corrompue ou si vous voulez tout simplement faire table rase." L["reset_desc"] = "Réinitialise le profil actuel au cas où votre configuration est corrompue ou si vous voulez tout simplement faire table rase."
L["reset_sub"] = "Réinitialise le profil actuel avec les paramètres par défaut." L["reset_sub"] = "Réinitialise le profil actuel avec les paramètres par défaut."
elseif LOCALE == "koKR" then elseif LOCALE == "koKR" then
L["choose"] = "저장 중인 프로필" L["choose"] = "기존 프로필"
L["choose_desc"] = "입력창에 새로운 이름을 입력하거나 저장 중인 프로필 중 하나를 선택하여 새로운 프로필을 만들 수 있습니다." L["choose_desc"] = "편집 상자에 이름을 입력하여 새로운 프로필을 만들거나 이미 존재하는 프로필 중 하나를 선택할 수 있습니다."
L["choose_sub"] = "현재 이용할 수 있는 프로필 중 하나를 선택합니다." L["choose_sub"] = "현재 이용할 수 있는 프로필 중 하나를 선택합니다."
L["copy"] = "복사해오기" L["copy"] = "복사해 올 프로필"
L["copy_desc"] = "현재 사용 중인 프로필에 선택한 프로필의 설정을 복사합니다." L["copy_desc"] = "기존 프로필의 설정을 현재 활성화된 프로필로 복사합니다."
L["current"] = "현재 프로필:" L["current"] = "현재 프로필:"
L["default"] = "기본값" L["default"] = "기본값"
L["delete"] = "프로필 삭제" L["delete"] = "프로필 삭제"
L["delete_confirm"] = "정말로 선택한 프로필을 삭제할까요?" L["delete_confirm"] = "선택한 프로필을 삭제하시겠습니까?"
L["delete_desc"] = "저장 공간 절약과 SavedVariables 파일의 정리를 위해 데이터베이스에서 사용하지 않는 프로필을 삭제하세요." L["delete_desc"] = "데이터베이스에서 기존 프로필과 사용하지 않는 프로필을 삭제하여 공간을 절약하고 SavedVariables 파일을 정리합니다."
L["delete_sub"] = "데이터베이스의 프로필을 삭제합니다." L["delete_sub"] = "데이터베이스에서 프로필을 삭제합니다."
L["intro"] = "활성 데이터베이스 프로필을 변경할 수 있고, 각 캐릭터 별로 다른 설정을 할 수 있습니다." L["intro"] = "활성 데이터베이스 프로필을 변경할 수 있으며, 모든 캐릭터마다 서로 다른 설정을 지정할 수 있습니다."
L["name_too_long"] = "프로필 이름은 50자리를 초과할 수 없습니다."
L["new"] = "새로운 프로필" L["new"] = "새로운 프로필"
L["new_sub"] = "새로운 프로필을 만듭니다." L["new_sub"] = "비어 있는 프로필을 새로 만듭니다."
L["profiles"] = "프로필" L["profiles"] = "프로필"
L["profiles_sub"] = "프로필 관리" L["profiles_sub"] = "프로필 관리"
L["reset"] = "프로필 초기화" L["reset"] = "프로필 재설정"
L["reset_desc"] = "설정이 깨졌거나 처음부터 다시 설정을 원하는 경우, 현재 프로필을 기본값으로 초기화하세요." L["reset_desc"] = "구성이 손상되었거나 처음부터 다시 시작하고 싶은 경우 현재 프로필을 기본값으로 재설정하세요."
L["reset_sub"] = "현재 프로필을 기본값으로 초기화합니다" L["reset_sub"] = "현재 프로필을 기본값으로 재설정합니다"
elseif LOCALE == "esES" or LOCALE == "esMX" then elseif LOCALE == "esES" or LOCALE == "esMX" then
L["choose"] = "Perfiles existentes" L["choose"] = "Perfiles existentes"
L["choose_desc"] = "Puedes crear un nuevo perfil introduciendo un nombre en el recuadro o puedes seleccionar un perfil de los ya existentes." L["choose_desc"] = "Puedes crear un nuevo perfil introduciendo un nombre en el recuadro o puedes seleccionar un perfil de los ya existentes."
@@ -116,6 +120,7 @@ elseif LOCALE == "esES" or LOCALE == "esMX" then
L["delete_desc"] = "Borra los perfiles existentes y sin uso de la base de datos para ganar espacio y limpiar el archivo SavedVariables." L["delete_desc"] = "Borra los perfiles existentes y sin uso de la base de datos para ganar espacio y limpiar el archivo SavedVariables."
L["delete_sub"] = "Borra un perfil de la base de datos." L["delete_sub"] = "Borra un perfil de la base de datos."
L["intro"] = "Puedes cambiar el perfil activo de tal manera que cada personaje tenga diferentes configuraciones." L["intro"] = "Puedes cambiar el perfil activo de tal manera que cada personaje tenga diferentes configuraciones."
L["name_too_long"] = "Los nombres de perfil no pueden exceder los 50 caracteres."
L["new"] = "Nuevo" L["new"] = "Nuevo"
L["new_sub"] = "Crear un nuevo perfil vacio." L["new_sub"] = "Crear un nuevo perfil vacio."
L["profiles"] = "Perfiles" L["profiles"] = "Perfiles"
@@ -136,6 +141,7 @@ elseif LOCALE == "zhTW" then
L["delete_desc"] = "從資料庫裡刪除不再使用的設定檔,以節省空間,並且清理 SavedVariables 檔案。" L["delete_desc"] = "從資料庫裡刪除不再使用的設定檔,以節省空間,並且清理 SavedVariables 檔案。"
L["delete_sub"] = "從資料庫裡刪除一個設定檔。" L["delete_sub"] = "從資料庫裡刪除一個設定檔。"
L["intro"] = "您可以從資料庫中選擇一個設定檔來使用,如此就可以讓每個角色使用不同的設定。" L["intro"] = "您可以從資料庫中選擇一個設定檔來使用,如此就可以讓每個角色使用不同的設定。"
L["name_too_long"] = "設定檔名稱不能超過50個字元。"
L["new"] = "新建" L["new"] = "新建"
L["new_sub"] = "新建一個空的設定檔。" L["new_sub"] = "新建一個空的設定檔。"
L["profiles"] = "設定檔" L["profiles"] = "設定檔"
@@ -156,6 +162,7 @@ elseif LOCALE == "zhCN" then
L["delete_desc"] = "从数据库里删除不再使用的配置文件,以节省空间,并且清理SavedVariables文件。" L["delete_desc"] = "从数据库里删除不再使用的配置文件,以节省空间,并且清理SavedVariables文件。"
L["delete_sub"] = "从数据库里删除一个配置文件。" L["delete_sub"] = "从数据库里删除一个配置文件。"
L["intro"] = "你可以选择一个活动的数据配置文件,这样你的每个角色就可以拥有不同的设置值,可以给你的插件配置带来极大的灵活性。" L["intro"] = "你可以选择一个活动的数据配置文件,这样你的每个角色就可以拥有不同的设置值,可以给你的插件配置带来极大的灵活性。"
L["name_too_long"] = "配置文件名称不能超过50个字符。"
L["new"] = "新建" L["new"] = "新建"
L["new_sub"] = "新建一个空的配置文件。" L["new_sub"] = "新建一个空的配置文件。"
L["profiles"] = "配置文件" L["profiles"] = "配置文件"
@@ -166,36 +173,38 @@ elseif LOCALE == "zhCN" then
elseif LOCALE == "ruRU" then elseif LOCALE == "ruRU" then
L["choose"] = "Существующие профили" L["choose"] = "Существующие профили"
L["choose_desc"] = "Вы можете создать новый профиль, введя название в поле ввода, или выбрать один из уже существующих профилей." L["choose_desc"] = "Вы можете создать новый профиль, введя название в поле ввода, или выбрать один из уже существующих профилей."
L["choose_sub"] = "Выбор одиного из уже доступных профилей" L["choose_sub"] = "Выбор одного из уже доступных профилей."
L["copy"] = "Скопировать из" L["copy"] = "Скопировать из"
L["copy_desc"] = "Скопировать настройки из выбранного профиля в активный." L["copy_desc"] = "Копирование настроек из выбранного профиля в активный."
L["current"] = "Текущий профиль:" L["current"] = "Текущий профиль:"
L["default"] = "По умолчанию" L["default"] = "По умолчанию"
L["delete"] = "Удалить профиль" L["delete"] = "Удалить профиль"
L["delete_confirm"] = "Вы уверены, что вы хотите удалить выбранный профиль?" L["delete_confirm"] = "Вы уверены, что хотите удалить выбранный профиль?"
L["delete_desc"] = "Удалить существующий и неиспользуемый профиль из БД для сохранения места, и очистить SavedVariables файл." L["delete_desc"] = "Удаление существующего и неиспользуемого профиля из базы данных для сохранения места, и очистка файла SavedVariables."
L["delete_sub"] = "Удаление профиля из БД" L["delete_sub"] = "Удаление профиля из базы данных."
L["intro"] = "Изменяя активный профиль, вы можете задать различные настройки модификаций для каждого персонажа." L["intro"] = "Изменяя активный профиль, Вы можете задать разные настройки для каждого персонажа."
L["name_too_long"] = "Имена профилей не могут превышать 50 символов."
L["new"] = "Новый" L["new"] = "Новый"
L["new_sub"] = "Создать новый чистый профиль" L["new_sub"] = "Создание нового чистого профиля."
L["profiles"] = "Профили" L["profiles"] = "Профили"
L["profiles_sub"] = "Управление профилями" L["profiles_sub"] = "Управление профилями"
L["reset"] = "Сброс профиля" L["reset"] = "Сбросить профиль"
L["reset_desc"] = "Сбросить текущий профиль к стандартным настройкам, если ваша конфигурация испорчена или вы хотите настроить всё заново." L["reset_desc"] = "Сброс текущего профиля к стандартным настройкам, если Ваша конфигурация испорчена или Вы хотите настроить все заново."
L["reset_sub"] = "Сброс текущего профиля на стандартный" L["reset_sub"] = "Сброс текущего профиля на стандартный"
elseif LOCALE == "itIT" then elseif LOCALE == "itIT" then
L["choose"] = "Profili Esistenti" L["choose"] = "Profili Esistenti"
L["choose_desc"] = "Puoi creare un nuovo profilo digitando il nome della casella di testo, oppure scegliendone uno tra i profili già esistenti." L["choose_desc"] = "Puoi creare un nuovo profilo digitando il nome della casella di testo, oppure scegliendone uno tra i profili già esistenti."
L["choose_sub"] = "Seleziona uno dei profili attualmente disponibili." L["choose_sub"] = "Seleziona uno dei profili attualmente disponibili."
L["copy"] = "Copia Da" L["copy"] = "Copia Da"
L["copy_desc"] = "Copia le impostazioni da un profilo esistente, nel profilo attivo in questo momento." L["copy_desc"] = "Copia le impostazioni da un profilo esistente nel profilo attivo in questo momento."
L["current"] = "Profilo Attivo:" L["current"] = "Profilo Attivo:"
L["default"] = "Standard" L["default"] = "Predefinito"
L["delete"] = "Cancella un Profilo" L["delete"] = "Cancella un Profilo"
L["delete_confirm"] = "Sei sicuro di voler cancellare il profilo selezionato?" L["delete_confirm"] = "Sei sicuro di voler cancellare il profilo selezionato?"
L["delete_desc"] = "Cancella i profili non utilizzati dal database per risparmiare spazio e mantenere puliti i file di configurazione SavedVariables." L["delete_desc"] = "Cancella i profili non utilizzati dal database per risparmiare spazio e mantenere puliti i file di configurazione SavedVariables."
L["delete_sub"] = "Cancella un profilo dal Database." L["delete_sub"] = "Cancella un profilo dal Database."
L["intro"] = "Puoi cambiare il profilo attivo, in modo da usare impostazioni diverse per ogni personaggio." L["intro"] = "Puoi cambiare il profilo attivo, in modo da usare impostazioni diverse per ogni personaggio."
L["name_too_long"] = "Il nome del profilo non può superare i 50 caratteri."
L["new"] = "Nuovo" L["new"] = "Nuovo"
L["new_sub"] = "Crea un nuovo profilo vuoto." L["new_sub"] = "Crea un nuovo profilo vuoto."
L["profiles"] = "Profili" L["profiles"] = "Profili"
@@ -216,6 +225,7 @@ elseif LOCALE == "ptBR" then
L["delete_desc"] = "Remove perfis existentes e inutilizados do banco de dados para economizar espaço, e limpar o arquivo SavedVariables." L["delete_desc"] = "Remove perfis existentes e inutilizados do banco de dados para economizar espaço, e limpar o arquivo SavedVariables."
L["delete_sub"] = "Remove um perfil do banco de dados." L["delete_sub"] = "Remove um perfil do banco de dados."
L["intro"] = "Você pode alterar o perfil do banco de dados ativo, para que possa ter definições diferentes para cada personagem." L["intro"] = "Você pode alterar o perfil do banco de dados ativo, para que possa ter definições diferentes para cada personagem."
L["name_too_long"] = "O nome do perfil não pode exceder 50 caracteres."
L["new"] = "Novo" L["new"] = "Novo"
L["new_sub"] = "Cria um novo perfil vazio." L["new_sub"] = "Cria um novo perfil vazio."
L["profiles"] = "Perfis" L["profiles"] = "Perfis"
@@ -346,6 +356,7 @@ end
--[[ --[[
the real options table the real options table
]] ]]
local strlenutf8 = strlenutf8
local optionsTable = { local optionsTable = {
desc = { desc = {
order = 1, order = 1,
@@ -382,6 +393,15 @@ local optionsTable = {
order = 30, order = 30,
get = false, get = false,
set = "SetProfile", set = "SetProfile",
usage = L["name_too_long"],
validate = function(_, text)
local length = strlenutf8(text)
if length > 50 or length == 0 or text:find("^ +$") then
return false
end
return true
end,
width = 2,
}, },
choose = { choose = {
name = L["choose"], name = L["choose"],
@@ -392,6 +412,7 @@ local optionsTable = {
set = "SetProfile", set = "SetProfile",
values = "ListProfiles", values = "ListProfiles",
arg = "common", arg = "common",
width = 2,
}, },
copydesc = { copydesc = {
order = 50, order = 50,
@@ -408,6 +429,7 @@ local optionsTable = {
values = "ListProfiles", values = "ListProfiles",
disabled = "HasNoProfiles", disabled = "HasNoProfiles",
arg = "nocurrent", arg = "nocurrent",
width = 2,
}, },
deldesc = { deldesc = {
order = 70, order = 70,
@@ -426,6 +448,7 @@ local optionsTable = {
arg = "nocurrent", arg = "nocurrent",
confirm = true, confirm = true,
confirmText = L["delete_confirm"], confirmText = L["delete_confirm"],
width = 2,
}, },
} }
@@ -2,7 +2,7 @@
TreeGroup Container TreeGroup Container
Container that uses a tree control to switch between groups. Container that uses a tree control to switch between groups.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "TreeGroup", 47 local Type, Version = "TreeGroup", 49
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -206,7 +206,7 @@ local function Button_OnEnter(frame)
tooltip:SetOwner(frame, "ANCHOR_NONE") tooltip:SetOwner(frame, "ANCHOR_NONE")
tooltip:ClearAllPoints() tooltip:ClearAllPoints()
tooltip:SetPoint("LEFT",frame,"RIGHT") tooltip:SetPoint("LEFT",frame,"RIGHT")
tooltip:SetText(frame.text:GetText() or "", 1, .82, 0, true) tooltip:SetText(frame.text:GetText() or "", 1, .82, 0, 1, true)
tooltip:Show() tooltip:Show()
end end
@@ -387,10 +387,6 @@ local methods = {
["RefreshTree"] = function(self,scrollToSelection,fromOnUpdate) ["RefreshTree"] = function(self,scrollToSelection,fromOnUpdate)
local buttons = self.buttons local buttons = self.buttons
local lines = self.lines local lines = self.lines
for i, v in ipairs(buttons) do
v:Hide()
end
while lines[1] do while lines[1] do
local t = tremove(lines) local t = tremove(lines)
for k in pairs(t) do for k in pairs(t) do
@@ -499,6 +495,10 @@ local methods = {
buttonnum = buttonnum + 1 buttonnum = buttonnum + 1
end end
-- We hide the remaining buttons after updating others to avoid a blizzard bug that keeps them interactable even if hidden when hidden before updating the buttons.
for i = buttonnum, #buttons do
buttons[i]:Hide()
end
end, end,
["SetSelected"] = function(self, value) ["SetSelected"] = function(self, value)
@@ -1,7 +1,7 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Checkbox Widget Checkbox Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "CheckBox", 26 local Type, Version = "CheckBox", 27
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -97,7 +97,7 @@ local methods = {
if disabled then if disabled then
self.frame:Disable() self.frame:Disable()
self.text:SetTextColor(0.5, 0.5, 0.5) self.text:SetTextColor(0.5, 0.5, 0.5)
SetDesaturation(self.check, true) self.check:SetDesaturated(true)
if self.desc then if self.desc then
self.desc:SetTextColor(0.5, 0.5, 0.5) self.desc:SetTextColor(0.5, 0.5, 0.5)
end end
@@ -105,9 +105,9 @@ local methods = {
self.frame:Enable() self.frame:Enable()
self.text:SetTextColor(1, 1, 1) self.text:SetTextColor(1, 1, 1)
if self.tristate and self.checked == nil then if self.tristate and self.checked == nil then
SetDesaturation(self.check, true) self.check:SetDesaturated(true)
else else
SetDesaturation(self.check, false) self.check:SetDesaturated(false)
end end
if self.desc then if self.desc then
self.desc:SetTextColor(1, 1, 1) self.desc:SetTextColor(1, 1, 1)
@@ -119,15 +119,15 @@ local methods = {
local check = self.check local check = self.check
self.checked = value self.checked = value
if value then if value then
SetDesaturation(check, false) self.check:SetDesaturated(false)
check:Show() check:Show()
else else
--Nil is the unknown tristate value --Nil is the unknown tristate value
if self.tristate and value == nil then if self.tristate and value == nil then
SetDesaturation(check, true) self.check:SetDesaturated(true)
check:Show() check:Show()
else else
SetDesaturation(check, false) self.check:SetDesaturated(false)
check:Hide() check:Hide()
end end
end end
@@ -1,7 +1,7 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
ColorPicker Widget ColorPicker Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "ColorPicker", 25 local Type, Version = "ColorPicker", 29
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -11,13 +11,24 @@ local pairs = pairs
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
-- Unfortunately we have no way to realistically detect if a client uses inverted alpha
-- as no API will tell you. Wrath uses the old colorpicker, era uses the new one, both are inverted
local INVERTED_ALPHA = (WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE and WOW_PROJECT_ID ~= WOW_PROJECT_CAMELOT)
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Support functions Support functions
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local function ColorCallback(self, r, g, b, a, isAlpha) local function ColorCallback(self, r, g, b, a, isAlpha)
if INVERTED_ALPHA and a then
a = 1 - a
end
if not self.HasAlpha then if not self.HasAlpha then
a = 1 a = 1
end end
-- no change, skip update
if r == self.r and g == self.g and b == self.b and a == self.a then
return
end
self:SetColor(r, g, b, a) self:SetColor(r, g, b, a)
if ColorPickerFrame:IsVisible() then if ColorPickerFrame:IsVisible() then
--colorpicker is still open --colorpicker is still open
@@ -50,30 +61,63 @@ local function ColorSwatch_OnClick(frame)
ColorPickerFrame:SetFrameLevel(frame:GetFrameLevel() + 10) ColorPickerFrame:SetFrameLevel(frame:GetFrameLevel() + 10)
ColorPickerFrame:SetClampedToScreen(true) ColorPickerFrame:SetClampedToScreen(true)
ColorPickerFrame.func = function() if ColorPickerFrame.SetupColorPickerAndShow then -- 10.2.5 color picker overhaul
local r, g, b = ColorPickerFrame:GetColorRGB() local r2, g2, b2, a2 = self.r, self.g, self.b, (self.a or 1)
local a = 1 - OpacitySliderFrame:GetValue() if INVERTED_ALPHA then
ColorCallback(self, r, g, b, a) a2 = 1 - a2
end end
ColorPickerFrame.hasOpacity = self.HasAlpha local info = {
ColorPickerFrame.opacityFunc = function() swatchFunc = function()
local r, g, b = ColorPickerFrame:GetColorRGB() local r, g, b = ColorPickerFrame:GetColorRGB()
local a = 1 - OpacitySliderFrame:GetValue() local a = ColorPickerFrame:GetColorAlpha()
ColorCallback(self, r, g, b, a, true) ColorCallback(self, r, g, b, a)
end end,
local r, g, b, a = self.r, self.g, self.b, self.a hasOpacity = self.HasAlpha,
if self.HasAlpha then opacityFunc = function()
ColorPickerFrame.opacity = 1 - (a or 0) local r, g, b = ColorPickerFrame:GetColorRGB()
end local a = ColorPickerFrame:GetColorAlpha()
ColorPickerFrame:SetColorRGB(r, g, b) ColorCallback(self, r, g, b, a, true)
end,
opacity = a2,
ColorPickerFrame.cancelFunc = function() cancelFunc = function()
ColorCallback(self, r, g, b, a, true) ColorCallback(self, r2, g2, b2, a2, true)
end end,
ColorPickerFrame:Show() r = r2,
g = g2,
b = b2,
}
ColorPickerFrame:SetupColorPickerAndShow(info)
else
ColorPickerFrame.func = function()
local r, g, b = ColorPickerFrame:GetColorRGB()
local a = OpacitySliderFrame:GetValue()
ColorCallback(self, r, g, b, a)
end
ColorPickerFrame.hasOpacity = self.HasAlpha
ColorPickerFrame.opacityFunc = function()
local r, g, b = ColorPickerFrame:GetColorRGB()
local a = OpacitySliderFrame:GetValue()
ColorCallback(self, r, g, b, a, true)
end
local r, g, b, a = self.r, self.g, self.b, 1 - (self.a or 1)
if self.HasAlpha then
ColorPickerFrame.opacity = a
end
ColorPickerFrame:SetColorRGB(r, g, b)
ColorPickerFrame.cancelFunc = function()
ColorCallback(self, r, g, b, a, true)
end
ColorPickerFrame:Show()
end
end end
AceGUI:ClearFocus() AceGUI:ClearFocus()
end end
@@ -1,7 +1,7 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
EditBox Widget EditBox Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "EditBox", 28 local Type, Version = "EditBox", 29
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -10,7 +10,7 @@ local tostring, pairs = tostring, pairs
-- WoW APIs -- WoW APIs
local PlaySound = PlaySound local PlaySound = PlaySound
local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo local GetCursorInfo, ClearCursor = GetCursorInfo, ClearCursor
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
local _G = _G local _G = _G
@@ -19,7 +19,11 @@ Support functions
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
if not AceGUIEditBoxInsertLink then if not AceGUIEditBoxInsertLink then
-- upgradeable hook -- upgradeable hook
hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIEditBoxInsertLink(...) end) if ChatFrameUtil and ChatFrameUtil.InsertLink then
hooksecurefunc(ChatFrameUtil, "InsertLink", function(...) return _G.AceGUIEditBoxInsertLink(...) end)
elseif ChatEdit_InsertLink then
hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIEditBoxInsertLink(...) end)
end
end end
function _G.AceGUIEditBoxInsertLink(text) function _G.AceGUIEditBoxInsertLink(text)
@@ -76,12 +80,16 @@ end
local function EditBox_OnReceiveDrag(frame) local function EditBox_OnReceiveDrag(frame)
local self = frame.obj local self = frame.obj
local type, id, info = GetCursorInfo() local type, id, info, extra = GetCursorInfo()
local name local name
if type == "item" then if type == "item" then
name = info name = info
elseif type == "spell" then elseif type == "spell" then
name = GetSpellInfo(id, info) if C_Spell and C_Spell.GetSpellName then
name = C_Spell.GetSpellName(extra)
else
name = GetSpellInfo(id, info)
end
elseif type == "macro" then elseif type == "macro" then
name = GetMacroInfo(id) name = GetMacroInfo(id)
end end
@@ -1,7 +1,7 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Heading Widget Heading Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Heading", 20 local Type, Version = "Heading", 21
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -9,7 +9,7 @@ if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local pairs = pairs local pairs = pairs
-- WoW APIs -- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent, issecretvalue = CreateFrame, UIParent, issecretvalue
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Methods Methods
@@ -21,11 +21,16 @@ local methods = {
self:SetHeight(18) self:SetHeight(18)
end, end,
-- ["OnRelease"] = nil, ["OnRelease"] = function(self)
self.label:ClearText()
self.label:ClearAllPoints()
self.label:SetPoint("TOP")
self.label:SetPoint("BOTTOM")
end,
["SetText"] = function(self, text) ["SetText"] = function(self, text)
self.label:SetText(text or "") self.label:SetText(text or "")
if text and text ~= "" then if issecretvalue(text) or (text and text ~= "") then
self.left:SetPoint("RIGHT", self.label, "LEFT", -5, 0) self.left:SetPoint("RIGHT", self.label, "LEFT", -5, 0)
self.right:Show() self.right:Show()
else else
@@ -1,7 +1,7 @@
--[[----------------------------------------------------------------------------- --[[-----------------------------------------------------------------------------
Icon Widget Icon Widget
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Icon", 21 local Type, Version = "Icon", 22
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -67,6 +67,11 @@ local methods = {
end end
end, end,
["SetImageByAtlas"] = function(self, atlasString)
local image = self.image
image:SetAtlas(atlasString)
end,
["SetImageSize"] = function(self, width, height) ["SetImageSize"] = function(self, width, height)
self.image:SetWidth(width) self.image:SetWidth(width)
self.image:SetHeight(height) self.image:SetHeight(height)
@@ -2,7 +2,7 @@
Keybinding Widget Keybinding Widget
Set Keybindings in the Config UI. Set Keybindings in the Config UI.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Keybinding", 26 local Type, Version = "Keybinding", 27
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -31,12 +31,14 @@ local function Keybinding_OnClick(frame, button)
if self.waitingForKey then if self.waitingForKey then
frame:EnableKeyboard(false) frame:EnableKeyboard(false)
frame:EnableMouseWheel(false) frame:EnableMouseWheel(false)
frame:EnableGamePadButton(false)
self.msgframe:Hide() self.msgframe:Hide()
frame:UnlockHighlight() frame:UnlockHighlight()
self.waitingForKey = nil self.waitingForKey = nil
else else
frame:EnableKeyboard(true) frame:EnableKeyboard(true)
frame:EnableMouseWheel(true) frame:EnableMouseWheel(true)
frame:EnableGamePadButton(true)
self.msgframe:Show() self.msgframe:Show()
frame:LockHighlight() frame:LockHighlight()
self.waitingForKey = true self.waitingForKey = true
@@ -72,6 +74,7 @@ local function Keybinding_OnKeyDown(frame, key)
frame:EnableKeyboard(false) frame:EnableKeyboard(false)
frame:EnableMouseWheel(false) frame:EnableMouseWheel(false)
frame:EnableGamePadButton(false)
self.msgframe:Hide() self.msgframe:Hide()
frame:UnlockHighlight() frame:UnlockHighlight()
self.waitingForKey = nil self.waitingForKey = nil
@@ -119,6 +122,7 @@ local methods = {
self:SetDisabled(false) self:SetDisabled(false)
self.button:EnableKeyboard(false) self.button:EnableKeyboard(false)
self.button:EnableMouseWheel(false) self.button:EnableMouseWheel(false)
self.button:EnableGamePadButton(false)
end, end,
-- ["OnRelease"] = nil, -- ["OnRelease"] = nil,
@@ -195,10 +199,12 @@ local function Constructor()
button:SetScript("OnKeyDown", Keybinding_OnKeyDown) button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
button:SetScript("OnMouseDown", Keybinding_OnMouseDown) button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel) button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel)
button:SetScript("OnGamePadButtonDown", Keybinding_OnKeyDown)
button:SetPoint("BOTTOMLEFT") button:SetPoint("BOTTOMLEFT")
button:SetPoint("BOTTOMRIGHT") button:SetPoint("BOTTOMRIGHT")
button:SetHeight(24) button:SetHeight(24)
button:EnableKeyboard(false) button:EnableKeyboard(false)
button:EnableGamePadButton(false)
local text = button:GetFontString() local text = button:GetFontString()
text:SetPoint("LEFT", 7, 0) text:SetPoint("LEFT", 7, 0)
@@ -2,7 +2,7 @@
Label Widget Label Widget
Displays text and optionally an icon. Displays text and optionally an icon.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Label", 28 local Type, Version = "Label", 29
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -124,6 +124,13 @@ local methods = {
UpdateImageAnchor(self) UpdateImageAnchor(self)
end, end,
["SetImageByAtlas"] = function(self, atlasString)
self.imageshown = true
local image = self.image
image:SetAtlas(atlasString)
UpdateImageAnchor(self)
end,
["SetFont"] = function(self, font, height, flags) ["SetFont"] = function(self, font, height, flags)
if not self.fontObject then if not self.fontObject then
self.fontObject = CreateFont("AceGUI30LabelFont" .. AceGUI:GetNextWidgetNum(Type)) self.fontObject = CreateFont("AceGUI30LabelFont" .. AceGUI:GetNextWidgetNum(Type))
@@ -1,4 +1,4 @@
local Type, Version = "MultiLineEditBox", 32 local Type, Version = "MultiLineEditBox", 33
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -6,7 +6,7 @@ if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local pairs = pairs local pairs = pairs
-- WoW APIs -- WoW APIs
local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor local GetCursorInfo, ClearCursor = GetCursorInfo, ClearCursor
local CreateFrame, UIParent = CreateFrame, UIParent local CreateFrame, UIParent = CreateFrame, UIParent
local _G = _G local _G = _G
@@ -16,7 +16,11 @@ Support functions
if not AceGUIMultiLineEditBoxInsertLink then if not AceGUIMultiLineEditBoxInsertLink then
-- upgradeable hook -- upgradeable hook
hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIMultiLineEditBoxInsertLink(...) end) if ChatFrameUtil and ChatFrameUtil.InsertLink then
hooksecurefunc(ChatFrameUtil, "InsertLink", function(...) return _G.AceGUIMultiLineEditBoxInsertLink(...) end)
elseif ChatEdit_InsertLink then
hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIMultiLineEditBoxInsertLink(...) end)
end
end end
function _G.AceGUIMultiLineEditBoxInsertLink(text) function _G.AceGUIMultiLineEditBoxInsertLink(text)
@@ -100,9 +104,13 @@ local function OnMouseUp(self)
end end
local function OnReceiveDrag(self) -- EditBox / ScrollFrame local function OnReceiveDrag(self) -- EditBox / ScrollFrame
local type, id, info = GetCursorInfo() local type, id, info, extra = GetCursorInfo()
if type == "spell" then if type == "spell" then
info = GetSpellInfo(id, info) if C_Spell and C_Spell.GetSpellName then
info = C_Spell.GetSpellName(extra)
else
info = GetSpellInfo(id, info)
end
elseif type ~= "item" then elseif type ~= "item" then
return return
end end
@@ -2,7 +2,7 @@
Slider Widget Slider Widget
Graphical Slider, like, for Range values. Graphical Slider, like, for Range values.
-------------------------------------------------------------------------------]] -------------------------------------------------------------------------------]]
local Type, Version = "Slider", 23 local Type, Version = "Slider", 24
local AceGUI = LibStub and LibStub("AceGUI-3.0", true) local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -273,6 +273,7 @@ local function Constructor()
widget[method] = func widget[method] = func
end end
slider.obj, editbox.obj = widget, widget slider.obj, editbox.obj = widget, widget
C_Timer.After(0.3, function() editbox:SetText(" ") UpdateText(widget) end) -- Workaround for font loading issue, making the editboxes blank until the text is changed
return AceGUI:RegisterAsWidget(widget) return AceGUI:RegisterAsWidget(widget)
end end
@@ -1,5 +1,5 @@
--[[ $Id$ ]] --[[ $Id: CallbackHandler-1.0.lua 25 2022-12-12 15:02:36Z nevcairiel $ ]]
local MAJOR, MINOR = "CallbackHandler-1.0", 7 local MAJOR, MINOR = "CallbackHandler-1.0", 8
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
if not CallbackHandler then return end -- No upgrade needed if not CallbackHandler then return end -- No upgrade needed
@@ -7,21 +7,16 @@ if not CallbackHandler then return end -- No upgrade needed
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
-- Lua APIs -- Lua APIs
local error = error local securecallfunction, error = securecallfunction, error
local setmetatable, rawget = setmetatable, rawget local setmetatable, rawget = setmetatable, rawget
local next, select, pairs, type, tostring = next, select, pairs, type, tostring local next, select, pairs, type, tostring = next, select, pairs, type, tostring
local xpcall = xpcall
local function errorhandler(err)
return geterrorhandler()(err)
end
local function Dispatch(handlers, ...) local function Dispatch(handlers, ...)
local index, method = next(handlers) local index, method = next(handlers)
if not method then return end if not method then return end
repeat repeat
xpcall(method, errorhandler, ...) securecallfunction(method, ...)
index, method = next(handlers, index) index, method = next(handlers, index)
until not method until not method
end end
+378 -137
View File
@@ -1,4 +1,4 @@
--@curseforge-project-slug: libdbicon-1-0@
----------------------------------------------------------------------- -----------------------------------------------------------------------
-- LibDBIcon-1.0 -- LibDBIcon-1.0
-- --
@@ -6,7 +6,7 @@
-- --
local DBICON10 = "LibDBIcon-1.0" local DBICON10 = "LibDBIcon-1.0"
local DBICON10_MINOR = 44 -- Bump on changes local DBICON10_MINOR = 57 -- Bump on changes
if not LibStub then error(DBICON10 .. " requires LibStub.") end if not LibStub then error(DBICON10 .. " requires LibStub.") end
local ldb = LibStub("LibDataBroker-1.1", true) local ldb = LibStub("LibDataBroker-1.1", true)
if not ldb then error(DBICON10 .. " requires LibDataBroker-1.1.") end if not ldb then error(DBICON10 .. " requires LibDataBroker-1.1.") end
@@ -16,9 +16,8 @@ if not lib then return end
lib.objects = lib.objects or {} lib.objects = lib.objects or {}
lib.callbackRegistered = lib.callbackRegistered or nil lib.callbackRegistered = lib.callbackRegistered or nil
lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib) lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib)
lib.notCreated = lib.notCreated or {}
lib.radius = lib.radius or 5 lib.radius = lib.radius or 5
local next, Minimap, CreateFrame = next, Minimap, CreateFrame local next, Minimap, CreateFrame, AddonCompartmentFrame = next, Minimap, CreateFrame, AddonCompartmentFrame
lib.tooltip = lib.tooltip or CreateFrame("GameTooltip", "LibDBIconTooltip", UIParent, "GameTooltipTemplate") lib.tooltip = lib.tooltip or CreateFrame("GameTooltip", "LibDBIconTooltip", UIParent, "GameTooltipTemplate")
local isDraggingButton = false local isDraggingButton = false
@@ -26,6 +25,15 @@ function lib:IconCallback(event, name, key, value)
if lib.objects[name] then if lib.objects[name] then
if key == "icon" then if key == "icon" then
lib.objects[name].icon:SetTexture(value) lib.objects[name].icon:SetTexture(value)
if lib:IsButtonInCompartment(name) and lib:IsButtonCompartmentAvailable() then
local addonList = AddonCompartmentFrame.registeredAddons
for i =1, #addonList do
if addonList[i].text == name then
addonList[i].icon = value
return
end
end
end
elseif key == "iconCoords" then elseif key == "iconCoords" then
lib.objects[name].icon:UpdateCoord() lib.objects[name].icon:UpdateCoord()
elseif key == "iconR" then elseif key == "iconR" then
@@ -95,6 +103,33 @@ local function onLeave(self)
end end
end end
local function onEnterCompartment(self, menu)
local buttonName = menu.text
local object = lib.objects[buttonName]
if object and object.dataObject then
if object.dataObject.OnTooltipShow then
lib.tooltip:SetOwner(self, "ANCHOR_NONE")
lib.tooltip:SetPoint(getAnchors(self))
object.dataObject.OnTooltipShow(lib.tooltip)
lib.tooltip:Show()
elseif object.dataObject.OnEnter then
object.dataObject.OnEnter(self)
end
end
end
local function onLeaveCompartment(self, menu)
lib.tooltip:Hide()
local buttonName = menu.text
local object = lib.objects[buttonName]
if object and object.dataObject then
if object.dataObject.OnLeave then
object.dataObject.OnLeave(self)
end
end
end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local onDragStart, updatePosition local onDragStart, updatePosition
@@ -213,43 +248,39 @@ local function updateCoord(self)
self:SetTexCoord(coords[1] + deltaX, coords[2] - deltaX, coords[3] + deltaY, coords[4] - deltaY) self:SetTexCoord(coords[1] + deltaX, coords[2] - deltaX, coords[3] + deltaY, coords[4] - deltaY)
end end
local function createButton(name, object, db) local function createButton(name, object, db, customCompartmentIcon)
local button = CreateFrame("Button", "LibDBIcon10_"..name, Minimap) local button = CreateFrame("Button", "LibDBIcon10_"..name, Minimap)
button.dataObject = object button.dataObject = object
button.db = db button.db = db
lib.objects[name] = button
button:SetFrameStrata("MEDIUM") button:SetFrameStrata("MEDIUM")
if button.SetFixedFrameStrata then -- Classic support button:SetFixedFrameStrata(true)
button:SetFixedFrameStrata(true)
end
button:SetFrameLevel(8) button:SetFrameLevel(8)
if button.SetFixedFrameLevel then -- Classic support button:SetFixedFrameLevel(true)
button:SetFixedFrameLevel(true)
end
button:SetSize(31, 31)
button:RegisterForClicks("anyUp") button:RegisterForClicks("anyUp")
button:RegisterForDrag("LeftButton") button:RegisterForDrag("LeftButton")
button:SetHighlightTexture(136477) --"Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight" lib:ResetButtonHighlightTexture(name)
local overlay = button:CreateTexture(nil, "OVERLAY") lib:ResetButtonSize(name)
overlay:SetSize(53, 53)
overlay:SetTexture(136430) --"Interface\\Minimap\\MiniMap-TrackingBorder"
overlay:SetPoint("TOPLEFT")
local background = button:CreateTexture(nil, "BACKGROUND")
background:SetSize(20, 20)
background:SetTexture(136467) --"Interface\\Minimap\\UI-Minimap-Background"
background:SetPoint("TOPLEFT", 7, -5)
local icon = button:CreateTexture(nil, "ARTWORK")
icon:SetSize(17, 17)
icon:SetTexture(object.icon)
icon:SetPoint("TOPLEFT", 7, -6)
button.icon = icon
button.isMouseDown = false
local border = button:CreateTexture(nil, "OVERLAY")
button.border = border
lib:ResetButtonBorder(name)
local background = button:CreateTexture(nil, "BACKGROUND")
button.background = background
lib:ResetButtonBackground(name)
local icon = button:CreateTexture(nil, "ARTWORK")
icon:SetTexture(object.icon)
local r, g, b = icon:GetVertexColor() local r, g, b = icon:GetVertexColor()
icon:SetVertexColor(object.iconR or r, object.iconG or g, object.iconB or b) icon:SetVertexColor(object.iconR or r, object.iconG or g, object.iconB or b)
icon.UpdateCoord = updateCoord icon.UpdateCoord = updateCoord
icon:UpdateCoord() icon:UpdateCoord()
button.icon = icon
lib:ResetButtonIcon(name)
button.isMouseDown = false
button:SetScript("OnEnter", onEnter) button:SetScript("OnEnter", onEnter)
button:SetScript("OnLeave", onLeave) button:SetScript("OnLeave", onLeave)
button:SetScript("OnClick", onClick) button:SetScript("OnClick", onClick)
@@ -269,8 +300,6 @@ local function createButton(name, object, db)
animOut:SetStartDelay(1) animOut:SetStartDelay(1)
button.fadeOut:SetToFinalAlpha(true) button.fadeOut:SetToFinalAlpha(true)
lib.objects[name] = button
if lib.loggedIn then if lib.loggedIn then
updatePosition(button, db and db.minimapPos) updatePosition(button, db and db.minimapPos)
if not db or not db.hide then if not db or not db.hide then
@@ -279,23 +308,18 @@ local function createButton(name, object, db)
button:Hide() button:Hide()
end end
end end
lib.callbacks:Fire("LibDBIcon_IconCreated", button, name) -- Fire 'Icon Created' callback
end
-- We could use a metatable.__index on lib.objects, but then we'd create if db and db.showInCompartment then
-- the icons when checking things like :IsRegistered, which is not necessary. lib:AddButtonToCompartment(name, customCompartmentIcon)
local function check(name)
if lib.notCreated[name] then
createButton(name, lib.notCreated[name][1], lib.notCreated[name][2])
lib.notCreated[name] = nil
end end
lib.callbacks:Fire("LibDBIcon_IconCreated", button, name) -- Fire 'Icon Created' callback
end end
-- Wait a bit with the initial positioning to let any GetMinimapShape addons -- Wait a bit with the initial positioning to let any GetMinimapShape addons
-- load up. -- load up.
if not lib.loggedIn then if not lib.loggedIn then
local f = CreateFrame("Frame") local frame = CreateFrame("Frame")
f:SetScript("OnEvent", function(f) frame:SetScript("OnEvent", function(self)
for _, button in next, lib.objects do for _, button in next, lib.objects do
updatePosition(button, button.db and button.db.minimapPos) updatePosition(button, button.db and button.db.minimapPos)
if not button.db or not button.db.hide then if not button.db or not button.db.hide then
@@ -305,90 +329,9 @@ if not lib.loggedIn then
end end
end end
lib.loggedIn = true lib.loggedIn = true
f:SetScript("OnEvent", nil) self:SetScript("OnEvent", nil)
end) end)
f:RegisterEvent("PLAYER_LOGIN") frame:RegisterEvent("PLAYER_LOGIN")
end
local function getDatabase(name)
return lib.notCreated[name] and lib.notCreated[name][2] or lib.objects[name].db
end
function lib:Register(name, object, db)
if not object.icon then error("Can't register LDB objects without icons set!") end
if lib.objects[name] or lib.notCreated[name] then error(DBICON10.. ": Object '".. name .."' is already registered.") end
if not db or not db.hide then
createButton(name, object, db)
else
lib.notCreated[name] = {object, db}
end
end
function lib:Lock(name)
if not lib:IsRegistered(name) then return end
if lib.objects[name] then
lib.objects[name]:SetScript("OnDragStart", nil)
lib.objects[name]:SetScript("OnDragStop", nil)
end
local db = getDatabase(name)
if db then
db.lock = true
end
end
function lib:Unlock(name)
if not lib:IsRegistered(name) then return end
if lib.objects[name] then
lib.objects[name]:SetScript("OnDragStart", onDragStart)
lib.objects[name]:SetScript("OnDragStop", onDragStop)
end
local db = getDatabase(name)
if db then
db.lock = nil
end
end
function lib:Hide(name)
if not lib.objects[name] then return end
lib.objects[name]:Hide()
end
function lib:Show(name)
check(name)
local button = lib.objects[name]
if button then
button:Show()
updatePosition(button, button.db and button.db.minimapPos or button.minimapPos)
end
end
function lib:IsRegistered(name)
return (lib.objects[name] or lib.notCreated[name]) and true or false
end
function lib:Refresh(name, db)
check(name)
local button = lib.objects[name]
if db then
button.db = db
end
updatePosition(button, button.db and button.db.minimapPos or button.minimapPos)
if not button.db or not button.db.hide then
button:Show()
else
button:Hide()
end
if not button.db or not button.db.lock then
button:SetScript("OnDragStart", onDragStart)
button:SetScript("OnDragStop", onDragStop)
else
button:SetScript("OnDragStart", nil)
button:SetScript("OnDragStop", nil)
end
end
function lib:GetMinimapButton(name)
return lib.objects[name]
end end
do do
@@ -411,23 +354,100 @@ do
end end
Minimap:HookScript("OnEnter", OnMinimapEnter) Minimap:HookScript("OnEnter", OnMinimapEnter)
Minimap:HookScript("OnLeave", OnMinimapLeave) Minimap:HookScript("OnLeave", OnMinimapLeave)
end
function lib:ShowOnEnter(name, value) --------------------------------------------------------------------------------
local button = lib.objects[name] -- Button API
if button then --
if value then
button.showOnMouseover = true function lib:Register(name, object, db, customCompartmentIcon)
button.fadeOut:Stop() if not object.icon then error("Can't register LDB objects without icons set!") end
button:SetAlpha(0) if lib:GetMinimapButton(name) then error(DBICON10.. ": Object '".. name .."' is already registered.") end
else createButton(name, object, db, customCompartmentIcon)
button.showOnMouseover = false end
button.fadeOut:Stop()
button:SetAlpha(1) function lib:Lock(name)
end local button = lib:GetMinimapButton(name)
if button then
button:SetScript("OnDragStart", nil)
button:SetScript("OnDragStop", nil)
if button.db then
button.db.lock = true
end end
end end
end end
function lib:Unlock(name)
local button = lib:GetMinimapButton(name)
if button then
button:SetScript("OnDragStart", onDragStart)
button:SetScript("OnDragStop", onDragStop)
if button.db then
button.db.lock = nil
end
end
end
function lib:Hide(name)
local button = lib:GetMinimapButton(name)
if button then
button:Hide()
end
end
function lib:Show(name)
local button = lib:GetMinimapButton(name)
if button then
button:Show()
updatePosition(button, button.db and button.db.minimapPos or button.minimapPos)
end
end
function lib:IsRegistered(name)
return lib.objects[name] and true or false
end
function lib:Refresh(name, db)
local button = lib:GetMinimapButton(name)
if button then
if db then
button.db = db
end
updatePosition(button, button.db and button.db.minimapPos or button.minimapPos)
if not button.db or not button.db.hide then
button:Show()
else
button:Hide()
end
if not button.db or not button.db.lock then
button:SetScript("OnDragStart", onDragStart)
button:SetScript("OnDragStop", onDragStop)
else
button:SetScript("OnDragStart", nil)
button:SetScript("OnDragStop", nil)
end
end
end
function lib:ShowOnEnter(name, value)
local button = lib:GetMinimapButton(name)
if button then
if value then
button.showOnMouseover = true
button.fadeOut:Stop()
button:SetAlpha(0)
else
button.showOnMouseover = false
button.fadeOut:Stop()
button:SetAlpha(1)
end
end
end
function lib:GetMinimapButton(name)
return lib.objects[name]
end
function lib:GetButtonList() function lib:GetButtonList()
local t = {} local t = {}
for name in next, lib.objects do for name in next, lib.objects do
@@ -449,9 +469,224 @@ function lib:SetButtonToPosition(button, position)
updatePosition(lib.objects[button] or button, position) updatePosition(lib.objects[button] or button, position)
end end
-- Upgrade! -- Button Configuration
function lib:SetButtonSize(name, size)
local button = lib:GetMinimapButton(name)
if button and type(size) == "number" then
button:SetSize(size, size)
end
end
function lib:ResetButtonSize(name)
local button = lib:GetMinimapButton(name)
if button then
button:SetSize(31, 31)
end
end
function lib:SetButtonHighlightTexture(name, highlightTexture)
local button = lib:GetMinimapButton(name)
if button and (type(highlightTexture) == "number" or type(highlightTexture) == "string") then
button:SetHighlightTexture(highlightTexture)
end
end
function lib:ResetButtonHighlightTexture(name)
local button = lib:GetMinimapButton(name)
if button then
button:SetHighlightTexture(136477) --"Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight"
end
end
-- Border configuration
function lib:RemoveButtonBorder(name)
local button = lib:GetMinimapButton(name)
if button.border then
button.border:Hide()
end
end
function lib:SetButtonBorder(name, borderTexture, size, framePoint, offsetX, offsetY)
local button = lib:GetMinimapButton(name)
if button.border then
lib:ResetButtonBorder(name)
if type(borderTexture) == "number" or type(borderTexture) == "string" then
button.border:SetTexture(borderTexture)
end
if type(size) == "number" then
button.border:SetSize(size, size)
end
if type(framePoint) == "string" then
button.border:ClearAllPoints()
button.border:SetPoint(framePoint, type(offsetX) == "number" and offsetX or 0, type(offsetY) == "number" and offsetY or 0)
end
end
end
function lib:ResetButtonBorder(name)
local button = lib:GetMinimapButton(name)
if button.border then
button.border:Show()
button.border:ClearAllPoints()
button.border:SetPoint("TOPLEFT", 0, 0)
button.border:SetTexture(136430) --"Interface\\Minimap\\MiniMap-TrackingBorder"
if lib:IsButtonCompartmentAvailable() then
button.border:SetSize(50, 50)
else
button.border:SetSize(53, 53)
end
end
end
-- Background configuration
function lib:RemoveButtonBackground(name)
local button = lib:GetMinimapButton(name)
if button.background then
button.background:Hide()
end
end
function lib:SetButtonBackground(name, backgroundTexture, size, framePoint, offsetX, offsetY)
local button = lib:GetMinimapButton(name)
if button.background then
lib:ResetButtonBackground(name)
if type(backgroundTexture) == "number" or type(backgroundTexture) == "string" then
button.background:SetTexture(backgroundTexture)
end
if type(size) == "number" then
button.background:SetSize(size, size)
end
if type(framePoint) == "string" then
button.background:ClearAllPoints()
button.background:SetPoint(framePoint, type(offsetX) == "number" and offsetX or 0, type(offsetY) == "number" and offsetY or 0)
end
end
end
function lib:ResetButtonBackground(name)
local button = lib:GetMinimapButton(name)
if button.background then
button.background:Show()
button.background:ClearAllPoints()
button.background:SetTexture(136467) --"Interface\\Minimap\\UI-Minimap-Background"
if lib:IsButtonCompartmentAvailable() then
button.background:SetSize(24, 24)
button.background:SetPoint("CENTER", 0, 0)
else
button.background:SetSize(20, 20)
button.background:SetPoint("TOPLEFT", 7, -5)
end
end
end
-- Icon Configuration
function lib:SetButtonIcon(name, iconTexture, size, framePoint, offsetX, offsetY)
local button = lib:GetMinimapButton(name)
if button.icon then
lib:ResetButtonIcon(name)
if type(iconTexture) == "number" or type(iconTexture) == "string" then
button.icon:SetTexture(iconTexture)
end
if type(size) == "number" then
button.icon:SetSize(size, size)
end
if type(framePoint) == "string" then
button.icon:ClearAllPoints()
button.icon:SetPoint(framePoint, type(offsetX) == "number" and offsetX or 0, type(offsetY) == "number" and offsetY or 0)
end
end
end
function lib:ResetButtonIcon(name)
local button = lib:GetMinimapButton(name)
if button.icon then
button.icon:SetTexture(button.dataObject.icon)
button.icon:UpdateCoord()
local r, g, b = button.icon:GetVertexColor()
button.icon:SetVertexColor(button.dataObject.iconR or r, button.dataObject.iconG or g, button.dataObject.iconB or b)
if lib:IsButtonCompartmentAvailable() then
button.icon:SetSize(18, 18)
button.icon:ClearAllPoints()
button.icon:SetPoint("CENTER")
else
button.icon:SetSize(17, 17)
button.icon:ClearAllPoints()
button.icon:SetPoint("TOPLEFT", 7, -6)
end
end
end
--------------------------------------------------------------------------------
-- Addon Compartment API
--
if AddonCompartmentFrame then
function lib:IsButtonCompartmentAvailable()
return true
end
else
function lib:IsButtonCompartmentAvailable()
return false
end
end
function lib:IsButtonInCompartment(buttonName)
local object = lib.objects[buttonName]
if object and object.db and object.db.showInCompartment then
return true
end
return false
end
function lib:AddButtonToCompartment(buttonName, customIcon)
if lib:IsButtonCompartmentAvailable() then
local object = lib.objects[buttonName]
if object and not object.compartmentData then
if object.db then
object.db.showInCompartment = true
end
object.compartmentData = {
text = buttonName,
icon = customIcon or object.dataObject.icon,
notCheckable = true,
registerForAnyClick = true,
func = function(_, menuInputData, menu)
object.dataObject.OnClick(menu, menuInputData.buttonName)
end,
funcOnEnter = onEnterCompartment,
funcOnLeave = onLeaveCompartment,
}
AddonCompartmentFrame:RegisterAddon(object.compartmentData)
end
end
end
function lib:RemoveButtonFromCompartment(buttonName)
if lib:IsButtonCompartmentAvailable() then
local object = lib.objects[buttonName]
if object and object.compartmentData then
for i = 1, #AddonCompartmentFrame.registeredAddons do
local entry = AddonCompartmentFrame.registeredAddons[i]
if entry == object.compartmentData then
object.compartmentData = nil
if object.db then
object.db.showInCompartment = nil
end
table.remove(AddonCompartmentFrame.registeredAddons, i)
AddonCompartmentFrame:UpdateDisplay()
return
end
end
end
end
end
--------------------------------------------------------------------------------
-- Upgrades
--
for name, button in next, lib.objects do for name, button in next, lib.objects do
local db = getDatabase(name) local db = button.db
if not db or not db.lock then if not db or not db.lock then
button:SetScript("OnDragStart", onDragStart) button:SetScript("OnDragStart", onDragStart)
button:SetScript("OnDragStop", onDragStop) button:SetScript("OnDragStop", onDragStop)
@@ -474,3 +709,9 @@ for name, button in next, lib.objects do
end end
end end
lib:SetButtonRadius(lib.radius) -- Upgrade to 40 lib:SetButtonRadius(lib.radius) -- Upgrade to 40
if lib.notCreated then -- Upgrade to 50
for name in next, lib.notCreated do
createButton(name, lib.notCreated[name][1], lib.notCreated[name][2])
end
lib.notCreated = nil
end
+2
View File
@@ -33,6 +33,8 @@ L.Error_InvalidCommand = "Ung\195\188ltiger Befehl"
L.Error_InvalidChannel = "Ung\195\188ltiger Kanal" L.Error_InvalidChannel = "Ung\195\188ltiger Kanal"
L.Error_InvalidWhisperTarget = "Ung\195\188ltiger Fl\195\188sterziel" L.Error_InvalidWhisperTarget = "Ung\195\188ltiger Fl\195\188sterziel"
L.Error_UnsupportedChannel = "Nicht unterst\195\188tzter Kanal" L.Error_UnsupportedChannel = "Nicht unterst\195\188tzter Kanal"
L.Chat_Lockdown_Notice = "Der Chat ist w\195\164hrend dieses Kampfes durch das Spiel gesperrt, Grichelde hält sich zurück."
L.Chat_Lockdown_Suffix = "(ignoriert von Grichelde)"
-- profiles -- profiles
L.Profiles_Available = "Verf\195\188gbare Profile:" L.Profiles_Available = "Verf\195\188gbare Profile:"
+2
View File
@@ -33,6 +33,8 @@ L.Error_InvalidCommand = "Invalid command"
L.Error_InvalidChannel = "Invalid channel" L.Error_InvalidChannel = "Invalid channel"
L.Error_InvalidWhisperTarget = "Invalid whisper target" L.Error_InvalidWhisperTarget = "Invalid whisper target"
L.Error_UnsupportedChannel = "Unsupported channel" L.Error_UnsupportedChannel = "Unsupported channel"
L.Chat_Lockdown_Notice = "Chat is locked by the game during this encounter. Grichelde will remain passive."
L.Chat_Lockdown_Suffix = "(ignored by Grichelde)"
-- profiles -- profiles
L.Profiles_Available = "Available profiles:" L.Profiles_Available = "Available profiles:"