diff --git a/CHANGELOG.md b/CHANGELOG.md
index 97cd242..33972f0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Upcoming] Version 0.8.0-beta - 2020-06-08
### Added
- handle replacement via slash command
+- emote detection
+
+## Version 0.7.2-beta - 2020-06-08
+### Added
+- minimap button
+### Changed
+- graphical move arrows
+###Fixed
+- crash on matches with 0-width
## Version 0.7.1-beta - 2020-06-07
### Added
diff --git a/Grichelde.lua b/Grichelde.lua
index 1a5dd07..54b6fe0 100644
--- a/Grichelde.lua
+++ b/Grichelde.lua
@@ -35,10 +35,10 @@ function Grichelde:OnInitialize()
self:UpgradeDatabase()
self.options, self.dialog = self:SetupOptions()
-
- -- populate UI from database
self:RefreshOptions("OnProfileChanged")
+ self.ldb, self.icon = self:MinimapButton()
+
self:SetupSlashCommands()
end
@@ -63,15 +63,16 @@ end
function Grichelde:HandleSlashCommand(input)
-- Show the GUI if no input is supplied, otherwise handle the chat input.
if self.functions.nilOrEmpty(input) then
- LibStub("AceConfigDialog-3.0"):Open(self.name)
+ self:OpenOptions()
else
-- handle slash ourselves
self:DebugPrint("Handle slash command: " .. input)
if input == "mappings" then
- self:ShowMappings()
- end
- if input == "options" then
+ self:ToogleMappings()
+ elseif input == "options" then
self:PrintOptions()
+ elseif input == "profile" then
+ self:PrintProfile()
end
end
end
\ No newline at end of file
diff --git a/Grichelde.toc b/Grichelde.toc
index 340c47c..1a1b823 100644
--- a/Grichelde.toc
+++ b/Grichelde.toc
@@ -3,7 +3,7 @@
## Title: Grichelde
## Notes: Replaces characters from the chat box
## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile
-## Version: 0.7.1-beta
+## Version: 0.7.2-beta
## Author: Teilzeit-Jedi
## eMail: tj@teilzeit-jedi.de
@@ -11,10 +11,10 @@
## X-Curse-Project-ID: 385480
## X-License: GPLv3
## X-Category: Chat/Communication
-## X-Credits: Teilzeit-Jedi, Nathan Pieper
+## X-Credits: Teilzeit-Jedi
## X-Embeds: Ace3
-## OptionalDeps: Ace3
+## OptionalDeps: Ace3, LibDataBroker, LibIcon
## SavedVariables: GricheldeDB
libs.xml
diff --git a/GricheldeChat.lua b/GricheldeChat.lua
index 9f78052..96c8a08 100644
--- a/GricheldeChat.lua
+++ b/GricheldeChat.lua
@@ -2,8 +2,8 @@
local _G = _G
local Grichelde = _G.Grichelde
-local nilOrEmpty, ipairs, spairs, tContains, tFilter, tInsert, tConcat, find, sub, isUpper, isLower, toUpper, toLower, trim, length
- = Grichelde.functions.nilOrEmpty, Grichelde.functions.ipairs, Grichelde.functions.spairs, Grichelde.functions.tContains, Grichelde.functions.tFilter, Grichelde.functions.tInsert, Grichelde.functions.tConcat,
+local IsAddOnLoaded, nilOrEmpty, ipairs, spairs, tContains, tFilter, tInsert, tConcat, find, sub, isUpper, isLower, toUpper, toLower, trim, length
+ = Grichelde.functions.IsAddOnLoaded, Grichelde.functions.nilOrEmpty, Grichelde.functions.ipairs, Grichelde.functions.spairs, Grichelde.functions.tContains, Grichelde.functions.tFilter, Grichelde.functions.tInsert, Grichelde.functions.tConcat,
Grichelde.functions.find, Grichelde.functions.sub, Grichelde.functions.isUpper, Grichelde.functions.isLower, Grichelde.functions.toUpper, Grichelde.functions.toLower, Grichelde.functions.trim, Grichelde.functions.length
--- Before a chat message is sent, check if replacement is required and replace the text accordingly.
@@ -27,7 +27,7 @@ end
function Grichelde:CheckAndReplace(message, type)
local text = message
if (self:CheckReplacement(text, type)) then
- if (_G.Misspelled) then
+ if (IsAddOnLoaded("Misspelled")) then
self:DebugPrint("Misspelled detected: cleansing message")
text = _G.Misspelled:RemoveHighlighting(text)
end
@@ -218,7 +218,7 @@ function Grichelde:ReplaceCharacters(text)
local oldResult = result
local pos1, pos2 = find(oldResult, search, pos)
- while (pos1 and pos2) do
+ while (pos1 and pos2 and pos1 <= pos2) do
self:TracePrint("pos1: %d, pos2: %d", pos1, pos2)
local pre = sub(result, 1, pos1 - 1 + offset)
local post = sub(result, pos2 + 1 + offset)
@@ -247,7 +247,7 @@ function Grichelde:ReplaceCharacters(text)
local lowerSearch = toLower(search)
local pos1, pos2 = find(lowerResult, lowerSearch, pos)
- while (pos1 and pos2) do
+ while (pos1 and pos2 and pos1 <= pos2) do
self:TracePrint("pos1: %d, pos2: %d", pos1, pos2)
local pre = sub(result, 1, pos1 - 1 + offset)
local match = sub(result, pos1 + offset, pos2 + offset)
diff --git a/GricheldeConstants.lua b/GricheldeConstants.lua
index b60c661..5f34dc9 100644
--- a/GricheldeConstants.lua
+++ b/GricheldeConstants.lua
@@ -9,7 +9,17 @@ Grichelde.LOG_LEVEL.TRACE = 2
Grichelde.MAPPING_OFFSET = 10
+Grichelde.ICONS = {}
+Grichelde.ICONS.MOVE_UP = "Interface\\MainMenuBar\\UI-MainMenu-ScrollUpButton-Up"
+Grichelde.ICONS.MOVE_DOWN = "Interface\\MainMenuBar\\UI-MainMenu-ScrollDownButton-Up"
+
-- colors:
+Grichelde.COLORS = {}
+Grichelde.COLORS.NORMAL = _G.NORMAL_FONT_COLOR
+Grichelde.COLORS.HIGHLIGHT = _G.HIGHLIGHT_FONT_COLOR
+Grichelde.COLORS.RED = _G.RED_FONT_COLOR
+Grichelde.COLORS.GREEN = _G.GREEN_FONT_COLOR
+
Grichelde.COLOR_CODES = {}
Grichelde.COLOR_CODES.PREFIX = "|c00FFAA00"
-- https://github.com/stoneharry/Misc-WoW-Stuff/blob/master/EoC%20Interface/FrameXML/Constants.lua
@@ -120,42 +130,43 @@ end
-- faster function lookups by mapping to local refs
Grichelde.functions = {}
-Grichelde.functions.type = _G.type
-Grichelde.functions.print = _G.print
-Grichelde.functions.nilOrEmpty = nilOrEmpty
-Grichelde.functions.pairs = _G.pairs
-Grichelde.functions.ipairs = _G.ipairs
-Grichelde.functions.spairs = spairs
-Grichelde.functions.tContains = _G.tContains
-Grichelde.functions.tFilter = tFilter
-Grichelde.functions.tInsert = _G.table.insert
-Grichelde.functions.tConcat = _G.table.concat
-Grichelde.functions.tSize = tSize
-Grichelde.functions.tSort = _G.table.sort
-Grichelde.functions.tClone = tClone
-Grichelde.functions.tNext = _G.next
-Grichelde.functions.setmetatable = _G.setmetatable
-Grichelde.functions.getmetatable = _G.getmetatable
-Grichelde.functions.select = _G.select
-Grichelde.functions.unpack = _G.unpack
-Grichelde.functions.find = _G.string.find
-Grichelde.functions.sub = _G.string.sub
-Grichelde.functions.gsub = _G.string.gsub
-Grichelde.functions.match = _G.strmatch
-Grichelde.functions.join = _G.strjoin
-Grichelde.functions.split = _G.strsplit
-Grichelde.functions.toUpper = _G.strupper
-Grichelde.functions.toLower = _G.strlower
-Grichelde.functions.isChar = isChar
-Grichelde.functions.isNumber = isNumber
-Grichelde.functions.isUpper = isUpper
-Grichelde.functions.isLower = isLower
-Grichelde.functions.isCapital = isCapital
-Grichelde.functions.format = _G.string.format
-Grichelde.functions.rep = _G.string.rep
-Grichelde.functions.trim = _G.strtrim
-Grichelde.functions.length = _G.string.len
-Grichelde.functions.toString = _G.tostring
-Grichelde.functions.toNumber = _G.tonumber
-Grichelde.functions.max = _G.math.max
-Grichelde.functions.min = _G.math.min
\ No newline at end of file
+Grichelde.functions.IsAddOnLoaded = _G.IsAddOnLoaded
+Grichelde.functions.type = _G.type
+Grichelde.functions.print = _G.print
+Grichelde.functions.nilOrEmpty = nilOrEmpty
+Grichelde.functions.pairs = _G.pairs
+Grichelde.functions.ipairs = _G.ipairs
+Grichelde.functions.spairs = spairs
+Grichelde.functions.tContains = _G.tContains
+Grichelde.functions.tFilter = tFilter
+Grichelde.functions.tInsert = _G.table.insert
+Grichelde.functions.tConcat = _G.table.concat
+Grichelde.functions.tSize = tSize
+Grichelde.functions.tSort = _G.table.sort
+Grichelde.functions.tClone = tClone
+Grichelde.functions.tNext = _G.next
+Grichelde.functions.setmetatable = _G.setmetatable
+Grichelde.functions.getmetatable = _G.getmetatable
+Grichelde.functions.select = _G.select
+Grichelde.functions.unpack = _G.unpack
+Grichelde.functions.find = _G.string.find
+Grichelde.functions.sub = _G.string.sub
+Grichelde.functions.gsub = _G.string.gsub
+Grichelde.functions.match = _G.strmatch
+Grichelde.functions.join = _G.strjoin
+Grichelde.functions.split = _G.strsplit
+Grichelde.functions.toUpper = _G.strupper
+Grichelde.functions.toLower = _G.strlower
+Grichelde.functions.isChar = isChar
+Grichelde.functions.isNumber = isNumber
+Grichelde.functions.isUpper = isUpper
+Grichelde.functions.isLower = isLower
+Grichelde.functions.isCapital = isCapital
+Grichelde.functions.format = _G.string.format
+Grichelde.functions.rep = _G.string.rep
+Grichelde.functions.trim = _G.strtrim
+Grichelde.functions.length = _G.string.len
+Grichelde.functions.toString = _G.tostring
+Grichelde.functions.toNumber = _G.tonumber
+Grichelde.functions.max = _G.math.max
+Grichelde.functions.min = _G.math.min
\ No newline at end of file
diff --git a/GricheldeDatabase.lua b/GricheldeDatabase.lua
index 19eab1f..b66a148 100644
--- a/GricheldeDatabase.lua
+++ b/GricheldeDatabase.lua
@@ -10,6 +10,9 @@ function Grichelde:GetDefaultConfig()
global = {},
profile = {
enabled = true,
+ minimapButton = {
+ hide = false
+ },
channels = {
["*"] = false,
say = true,
diff --git a/GricheldeOptions.lua b/GricheldeOptions.lua
index 00855d5..5e505ea 100644
--- a/GricheldeOptions.lua
+++ b/GricheldeOptions.lua
@@ -22,7 +22,15 @@ function Grichelde:CreateOptionsUI()
desc = self:Format(self.L.Options_Enabled_Desc, self.L.AddonName),
disabled = false,
},
-
+ minimapButton = {
+ order = 1,
+ type = "toggle",
+ name = self.L.Options_Minimap_Button_Name,
+ desc = self.L.Options_Minimap_Button_Desc,
+ set = function(info, val) self:ToogleMinimapButton(info, val) end,
+ get = function(info) return not self.db.profile.minimapButton.hide end,
+ disabled = false,
+ },
channels = {
order = 2,
type = "group",
@@ -184,28 +192,28 @@ function Grichelde:CreateMapping(offset)
moveUp = {
order = 10,
type = "execute",
- --name = self.L.Options_Mapping_MoveUp_Name,
+ -- name = self.L.Options_Mapping_MoveUp_Name,
name = "",
desc = self.L.Options_Mapping_MoveUp_Desc,
- image = "Interface\\ChatFrame\\UI-ChatIcon-ScrollUp-Up",
- width = 0.25,
+ image = Grichelde.ICONS.MOVE_UP,
+ width = 0.15,
func = function(info) self:MoveUp(info) end
},
moveDown = {
order = 11,
type = "execute",
- --name = self.L.Options_Mapping_MoveDown_Name,
+ -- name = self.L.Options_Mapping_MoveDown_Name,
name = "",
desc = self.L.Options_Mapping_MoveDown_Desc,
- image = "Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up",
- width = 0.25,
+ image = Grichelde.ICONS.MOVE_DOWN,
+ width = 0.15,
func = function(info) self:MoveDown(info) end
},
spacer = {
order = 18,
type = "description",
name = "",
- width = 1,
+ width = 1.2,
},
delete = {
order = 19,
@@ -221,14 +229,6 @@ function Grichelde:CreateMapping(offset)
}
end
---dropButton:SetWidth(24)
---dropButton:SetHeight(24)
---dropButton:SetPoint("TOPRIGHT", DRight, "TOPRIGHT", -16, -18)
---dropButton:SetNormalTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollDown-Up]])
---dropButton:SetPushedTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollDown-Down]])
---dropButton:SetDisabledTexture([[Interface\ChatFrame\UI-ChatIcon-ScrollDown-Disabled]])
---dropButton:SetHighlightTexture([[Interface\Buttons\UI-Common-MouseHilight]], "ADD")
-
function Grichelde:SetupOptions()
-- add DB-backed profiles to UI options
local options = self:CreateOptionsUI()
@@ -243,25 +243,6 @@ function Grichelde:SetupOptions()
return options, dialog
end
-function Grichelde:IsDisabled(info)
- if info.option.type == "group" then
- return false
- end
- return not self.db.profile.enabled
-end
-
-function Grichelde:MappingName(info)
--- self:TracePrint("MappingName : info")
--- self:TracePrint(info)
- local option = self.db.profile.replacements[info[2]]
-
- if nilOrEmpty(option.searchText) and nilOrEmpty(option.replaceText) then
- return self.L.Options_Mapping_EmptyMapping
- else
- return self:Format(self.L.Options_Mapping_Group_Name, option.searchText or "", option.replaceText or "")
- end
-end
-
function Grichelde:RefreshOptions(event)
self:DebugPrint("RefreshOptions : event:", event)
if event == "OnNewProfile" then
@@ -282,6 +263,87 @@ function Grichelde:RefreshOptions(event)
self:RefreshReplacements(self.db.profile.replacements)
end
+--- add Minimap button
+function Grichelde:MinimapButton()
+ local function toggleOptionsUI(_, button)
+ if button == 'LeftButton' then
+ self:ToggleOptions()
+ elseif button == 'RightButton' then
+ self:ToogleMappings()
+ end
+ end
+
+ local function tooltip(tooltip)
+ if not tooltip or not tooltip.AddLine then return end
+ tooltip:SetText(self.L.AddonName,
+ Grichelde.COLORS.HIGHLIGHT.r, Grichelde.COLORS.HIGHLIGHT.g, Grichelde.COLORS.HIGHLIGHT.b, Grichelde.COLORS.HIGHLIGHT.a
+ )
+
+ tooltip:AddDoubleLine(self.L.Options_Minimap_Tooltip_Options_Left, self.L.Options_Minimap_Tooltip_Options_Right,
+ Grichelde.COLORS.GREEN.r, Grichelde.COLORS.GREEN.g, Grichelde.COLORS.GREEN.b, Grichelde.COLORS.GREEN.a,
+ Grichelde.COLORS.NORMAL.r, Grichelde.COLORS.NORMAL.g, Grichelde.COLORS.NORMAL.b, Grichelde.COLORS.NORMAL.a
+ )
+ tooltip:AddDoubleLine(self.L.Options_Minimap_Tooltip_Mappings_Left, self.L.Options_Minimap_Tooltip_Mappings_Right,
+ Grichelde.COLORS.GREEN.r, Grichelde.COLORS.GREEN.g, Grichelde.COLORS.GREEN.b, Grichelde.COLORS.GREEN.a,
+ Grichelde.COLORS.NORMAL.r, Grichelde.COLORS.NORMAL.g, Grichelde.COLORS.NORMAL.b, Grichelde.COLORS.NORMAL.a
+ )
+ end
+
+ local ldb = LibStub("LibDataBroker-1.1"):NewDataObject(self.name, {
+ type = "launcher",
+ text = self.AddonName,
+ icon = "Interface\\Icons\\Spell_Holy_Silence",
+ --icon = ([[Interface\Addons\%s\%s]]):format(self.name, self.name),
+ OnClick = toggleOptionsUI,
+ OnRightClick = function() self:ShowMappings() end,
+ OnTooltipShow = tooltip,
+ })
+
+ local icon = LibStub("LibDBIcon-1.0")
+ self:DebugPrint("MinimapButton : hidden: ", self.db.profile.minimapButton.hide)
+ icon:Register(self.name, ldb, self.db.profile.minimapButton)
+
+ return ldb, icon
+end
+
+
+function Grichelde:ToggleOptions()
+ self:DebugPrint("MinimapButton : options open: ", self.dialog.OpenFrames[self.name])
+ if self.dialog.OpenFrames[self.name] then
+ self:CloseOptions()
+ else
+ self:OpenOptions()
+ end
+end
+
+function Grichelde:OpenOptions()
+ self.dialog:Open(self.name)
+end
+
+function Grichelde:CloseOptions()
+ self.dialog:Close(self.name)
+end
+
+function Grichelde:IsDisabled(info)
+ if info.option.type == "group" then
+ return false
+ end
+ return not self.db.profile.enabled
+end
+
+function Grichelde:MappingName(info)
+-- self:TracePrint("MappingName : info")
+-- self:TracePrint(info)
+ local option = self.db.profile.replacements[info[2]]
+
+ if nilOrEmpty(option.searchText) and nilOrEmpty(option.replaceText) then
+ return self.L.Options_Mapping_EmptyMapping
+ else
+ return self:Format(self.L.Options_Mapping_Group_Name, option.searchText or "", option.replaceText or "")
+ end
+end
+
+
--- Create UI options for rhe given replacement table (from DB).
--- Usually called with with self.db.profile.replacements
-- @param replacementsTable
@@ -440,3 +502,21 @@ function Grichelde:DeleteAllMappings()
self:RefreshOptions("DeleteAllMappings")
end
+
+function Grichelde:ToogleMinimapButton(info, val)
+ self:TracePrint("ToogleMinimapButton : info")
+ for i = 0, #info do
+ self:TracePrint("%d = %s", i, info[i])
+ end
+
+ self.db.profile.minimapButton.hide = not val
+ self:DebugPrint("ToogleMinimapButton : hidden: ", self.db.profile.minimapButton.hide)
+
+ if self.db.profile.minimapButton.hide then
+ self.icon:Hide(self.name);
+ else
+ self.icon:Show(self.name);
+ end
+end
+
+
diff --git a/GricheldeUpgrade.lua b/GricheldeUpgrade.lua
index db4c289..c91ff88 100644
--- a/GricheldeUpgrade.lua
+++ b/GricheldeUpgrade.lua
@@ -8,7 +8,7 @@ function Grichelde:Upgrade_To_v060()
self:PrefixedPrint(self.L.Upgrade_ToVersion, Grichelde.COLOR_CODES.ORANGE .. "0.6.0" .. Grichelde.COLOR_CODES.CLOSE)
local replacements = self.db.profile.replacements or {}
- self:DebugPrint("Upgrade_To_060 : old database")
+ self:DebugPrint("Upgrade_To_v060 : old database")
self:DebugPrint(replacements)
for _, replTable in pairs(replacements) do
@@ -16,7 +16,7 @@ function Grichelde:Upgrade_To_v060()
replTable["caseSensitive"] = nil
end
- self:DebugPrint("Upgrade_To_060 : new database")
+ self:DebugPrint("Upgrade_To_v060 : new database")
self:DebugPrint(replacements)
return 0, 6, 0
end
@@ -25,7 +25,7 @@ function Grichelde:Upgrade_To_v070()
self:PrefixedPrint(self.L.Upgrade_ToVersion, Grichelde.COLOR_CODES.ORANGE .. "0.7.0" .. Grichelde.COLOR_CODES.CLOSE)
local replacements = self.db.profile.replacements or {}
- self:DebugPrint("Upgrade_To_070 : old database")
+ self:DebugPrint("Upgrade_To_v070 : old database")
self:DebugPrint(replacements)
for _, replTable in pairs(replacements) do
@@ -33,16 +33,23 @@ function Grichelde:Upgrade_To_v070()
replTable["ignoreCase"] = nil
end
- self:DebugPrint("Upgrade_To_070 : new database")
+ self:DebugPrint("Upgrade_To_v070 : new database")
self:DebugPrint(replacements)
return 0, 7, 0
end
---[[
-function Grichelde:Upgrade_To_v071()
- return 0, 7, 1
+function Grichelde:Upgrade_To_v072()
+ self:PrefixedPrint(self.L.Upgrade_ToVersion, Grichelde.COLOR_CODES.ORANGE .. "0.7.2" .. Grichelde.COLOR_CODES.CLOSE)
+
+ self:DebugPrint("Upgrade_To_v072 : old database")
+ self:DebugPrint(self.db.profile)
+
+ self.db.profile["minimapButton"] = { hide = false }
+
+ self:DebugPrint("Upgrade_To_v072 : new database")
+ self:DebugPrint(self.db.profile)
+ return 0, 7, 2
end
-]]
function Grichelde:UpgradeDatabase()
local dbVersion = self.db.global.version or "0.0.0"
@@ -63,14 +70,12 @@ function Grichelde:UpgradeDatabase()
upgrade = upgrade + 1
major, minor, patch = self:Upgrade_To_v070(dbVersion)
end
---[[
if minor == 7 then
- if patch < 1 then
+ if patch < 2 then
upgrade = upgrade + 1
- major, minor, patch = self:Upgrade_To_v71(dbVersion)
+ major, minor, patch = self:Upgrade_To_v072(dbVersion)
end
end
-]]
end
if upgrade == 0 then
diff --git a/GricheldeUtils.lua b/GricheldeUtils.lua
index 2344df7..1c6dd92 100644
--- a/GricheldeUtils.lua
+++ b/GricheldeUtils.lua
@@ -172,6 +172,14 @@ function Grichelde:PrintOptions()
end, self.options.args.replacements.args)
end
+--- Print DB
+function Grichelde:PrintProfile()
+ self:PrefixedPrint(self.COLOR_CODES.PREFIX .. self.L.Debug_Profile .. self.COLOR_CODES.CLOSE)
+ self:LogPrint(-1, function(...)
+ print(self.COLOR_CODES.PREFIX .. self.L.AddonName .. self.COLOR_CODES.CLOSE .. ":", self:Format(...))
+ end, self.db.profile)
+end
+
--- Print DB replacements to chat frame
function Grichelde:PrintMappings()
self:PrefixedPrint(self.COLOR_CODES.PREFIX .. self.L.Debug_Mappings .. self.COLOR_CODES.CLOSE)
@@ -181,9 +189,11 @@ function Grichelde:PrintMappings()
end
--- Open UI windows with replacements in it
-function Grichelde:ShowMappings()
- if self.debugFrame and self.debugFrame:IsShown() then
- self.debugFrame:Release(self.debugFrame)
+function Grichelde:ToogleMappings()
+ local AceGUI = LibStub("AceGUI-3.0")
+
+ if self.debugFrame then
+ AceGUI:Release(self.debugFrame)
self.debugFrame = nil
else
local replacements = self.db.profile.replacements or {}
@@ -194,28 +204,40 @@ function Grichelde:ShowMappings()
end
end
- local AceGUI = LibStub("AceGUI-3.0")
local frame = AceGUI:Create("Frame");
frame:SetTitle(self.L.Debug_Mappings);
frame:SetStatusText(self:Format(self.L.Debug_Mappings_Found, repls))
frame:SetWidth(400);
- frame:SetHeight(600);
- frame:SetLayout("Fill");
-
- local function closeFrame() frame:Release(frame) end
+ frame:SetAutoAdjustHeight(true)
+ --frame:SetFullHeight(true)
+ frame:SetLayout("Flow");
+ local function closeFrame(widget) AceGUI:Release(widget); self.debugFrame = nil end
frame:SetCallback("OnClose", closeFrame)
+ local hint = AceGUI:Create("Label");
+ hint:SetText(self.L.Debug_Mappings_Hint)
+ hint:SetFullWidth(true)
+ frame:AddChild(hint);
+
+ local scroll = AceGUI:Create("ScrollFrame");
+ scroll:SetFullWidth(true)
+ scroll:SetFullHeight(true)
+ scroll:SetLayout("Fill");
+
local configBox = AceGUI:Create("MultiLineEditBox");
+ configBox:SetLabel("")
local text = ""
tPrint(replacements, 0, {}, function(s) text = text .. s .. "|n" end)
- configBox:SetLabel("")
configBox:SetText(text)
+ configBox:SetFullWidth(true)
+ configBox:SetFullHeight(true)
configBox:DisableButton(true)
--configBox:SetDisabled(true)
- configBox:SetNumLines(30);
+ configBox:SetNumLines(50);
configBox:SetFocus()
+ scroll:AddChild(configBox);
- frame:AddChild(configBox);
+ frame:AddChild(scroll);
self.debugFrame = frame
end
end
\ No newline at end of file
diff --git a/Libs/LibDBIcon-1.0/LibDBIcon-1.0.lua b/Libs/LibDBIcon-1.0/LibDBIcon-1.0.lua
new file mode 100644
index 0000000..e865bdf
--- /dev/null
+++ b/Libs/LibDBIcon-1.0/LibDBIcon-1.0.lua
@@ -0,0 +1,470 @@
+
+-----------------------------------------------------------------------
+-- LibDBIcon-1.0
+--
+-- Allows addons to easily create a lightweight minimap icon as an alternative to heavier LDB displays.
+--
+
+local DBICON10 = "LibDBIcon-1.0"
+local DBICON10_MINOR = 43 -- Bump on changes
+if not LibStub then error(DBICON10 .. " requires LibStub.") end
+local ldb = LibStub("LibDataBroker-1.1", true)
+if not ldb then error(DBICON10 .. " requires LibDataBroker-1.1.") end
+local lib = LibStub:NewLibrary(DBICON10, DBICON10_MINOR)
+if not lib then return end
+
+lib.objects = lib.objects or {}
+lib.callbackRegistered = lib.callbackRegistered or nil
+lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib)
+lib.notCreated = lib.notCreated or {}
+lib.radius = lib.radius or 5
+lib.tooltip = lib.tooltip or CreateFrame("GameTooltip", "LibDBIconTooltip", UIParent, "GameTooltipTemplate")
+local next, Minimap = next, Minimap
+local isDraggingButton = false
+
+function lib:IconCallback(event, name, key, value)
+ if lib.objects[name] then
+ if key == "icon" then
+ lib.objects[name].icon:SetTexture(value)
+ elseif key == "iconCoords" then
+ lib.objects[name].icon:UpdateCoord()
+ elseif key == "iconR" then
+ local _, g, b = lib.objects[name].icon:GetVertexColor()
+ lib.objects[name].icon:SetVertexColor(value, g, b)
+ elseif key == "iconG" then
+ local r, _, b = lib.objects[name].icon:GetVertexColor()
+ lib.objects[name].icon:SetVertexColor(r, value, b)
+ elseif key == "iconB" then
+ local r, g = lib.objects[name].icon:GetVertexColor()
+ lib.objects[name].icon:SetVertexColor(r, g, value)
+ end
+ end
+end
+if not lib.callbackRegistered then
+ ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__icon", "IconCallback")
+ ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconCoords", "IconCallback")
+ ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconR", "IconCallback")
+ ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconG", "IconCallback")
+ ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__iconB", "IconCallback")
+ lib.callbackRegistered = true
+end
+
+local function getAnchors(frame)
+ local x, y = frame:GetCenter()
+ if not x or not y then return "CENTER" end
+ local hhalf = (x > UIParent:GetWidth()*2/3) and "RIGHT" or (x < UIParent:GetWidth()/3) and "LEFT" or ""
+ local vhalf = (y > UIParent:GetHeight()/2) and "TOP" or "BOTTOM"
+ return vhalf..hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP")..hhalf
+end
+
+local function onEnter(self)
+ if isDraggingButton then return end
+
+ for _, button in next, lib.objects do
+ if button.showOnMouseover then
+ button.fadeOut:Stop()
+ button:SetAlpha(1)
+ end
+ end
+
+ local obj = self.dataObject
+ if obj.OnTooltipShow then
+ lib.tooltip:SetOwner(self, "ANCHOR_NONE")
+ lib.tooltip:SetPoint(getAnchors(self))
+ obj.OnTooltipShow(lib.tooltip)
+ lib.tooltip:Show()
+ elseif obj.OnEnter then
+ obj.OnEnter(self)
+ end
+end
+
+local function onLeave(self)
+ lib.tooltip:Hide()
+
+ if not isDraggingButton then
+ for _, button in next, lib.objects do
+ if button.showOnMouseover then
+ button.fadeOut:Play()
+ end
+ end
+ end
+
+ local obj = self.dataObject
+ if obj.OnLeave then
+ obj.OnLeave(self)
+ end
+end
+
+--------------------------------------------------------------------------------
+
+local onDragStart, updatePosition
+
+do
+ local minimapShapes = {
+ ["ROUND"] = {true, true, true, true},
+ ["SQUARE"] = {false, false, false, false},
+ ["CORNER-TOPLEFT"] = {false, false, false, true},
+ ["CORNER-TOPRIGHT"] = {false, false, true, false},
+ ["CORNER-BOTTOMLEFT"] = {false, true, false, false},
+ ["CORNER-BOTTOMRIGHT"] = {true, false, false, false},
+ ["SIDE-LEFT"] = {false, true, false, true},
+ ["SIDE-RIGHT"] = {true, false, true, false},
+ ["SIDE-TOP"] = {false, false, true, true},
+ ["SIDE-BOTTOM"] = {true, true, false, false},
+ ["TRICORNER-TOPLEFT"] = {false, true, true, true},
+ ["TRICORNER-TOPRIGHT"] = {true, false, true, true},
+ ["TRICORNER-BOTTOMLEFT"] = {true, true, false, true},
+ ["TRICORNER-BOTTOMRIGHT"] = {true, true, true, false},
+ }
+
+ local rad, cos, sin, sqrt, max, min = math.rad, math.cos, math.sin, math.sqrt, math.max, math.min
+ function updatePosition(button, position)
+ local angle = rad(position or 225)
+ local x, y, q = cos(angle), sin(angle), 1
+ if x < 0 then q = q + 1 end
+ if y > 0 then q = q + 2 end
+ local minimapShape = GetMinimapShape and GetMinimapShape() or "ROUND"
+ local quadTable = minimapShapes[minimapShape]
+ local w = (Minimap:GetWidth() / 2) + lib.radius
+ local h = (Minimap:GetHeight() / 2) + lib.radius
+ if quadTable[q] then
+ x, y = x*w, y*h
+ else
+ local diagRadiusW = sqrt(2*(w)^2)-10
+ local diagRadiusH = sqrt(2*(h)^2)-10
+ x = max(-w, min(x*diagRadiusW, w))
+ y = max(-h, min(y*diagRadiusH, h))
+ end
+ button:SetPoint("CENTER", Minimap, "CENTER", x, y)
+ end
+end
+
+local function onClick(self, b)
+ if self.dataObject.OnClick then
+ self.dataObject.OnClick(self, b)
+ end
+end
+
+local function onMouseDown(self)
+ self.isMouseDown = true
+ self.icon:UpdateCoord()
+end
+
+local function onMouseUp(self)
+ self.isMouseDown = false
+ self.icon:UpdateCoord()
+end
+
+do
+ local deg, atan2 = math.deg, math.atan2
+ local function onUpdate(self)
+ local mx, my = Minimap:GetCenter()
+ local px, py = GetCursorPosition()
+ local scale = Minimap:GetEffectiveScale()
+ px, py = px / scale, py / scale
+ local pos = 225
+ if self.db then
+ pos = deg(atan2(py - my, px - mx)) % 360
+ self.db.minimapPos = pos
+ else
+ pos = deg(atan2(py - my, px - mx)) % 360
+ self.minimapPos = pos
+ end
+ updatePosition(self, pos)
+ end
+
+ function onDragStart(self)
+ self:LockHighlight()
+ self.isMouseDown = true
+ self.icon:UpdateCoord()
+ self:SetScript("OnUpdate", onUpdate)
+ isDraggingButton = true
+ lib.tooltip:Hide()
+ for _, button in next, lib.objects do
+ if button.showOnMouseover then
+ button.fadeOut:Stop()
+ button:SetAlpha(1)
+ end
+ end
+ end
+end
+
+local function onDragStop(self)
+ self:SetScript("OnUpdate", nil)
+ self.isMouseDown = false
+ self.icon:UpdateCoord()
+ self:UnlockHighlight()
+ isDraggingButton = false
+ for _, button in next, lib.objects do
+ if button.showOnMouseover then
+ button.fadeOut:Play()
+ end
+ end
+end
+
+local defaultCoords = {0, 1, 0, 1}
+local function updateCoord(self)
+ local coords = self:GetParent().dataObject.iconCoords or defaultCoords
+ local deltaX, deltaY = 0, 0
+ if not self:GetParent().isMouseDown then
+ deltaX = (coords[2] - coords[1]) * 0.05
+ deltaY = (coords[4] - coords[3]) * 0.05
+ end
+ self:SetTexCoord(coords[1] + deltaX, coords[2] - deltaX, coords[3] + deltaY, coords[4] - deltaY)
+end
+
+local function createButton(name, object, db)
+ local button = CreateFrame("Button", "LibDBIcon10_"..name, Minimap)
+ button.dataObject = object
+ button.db = db
+ button:SetFrameStrata("MEDIUM")
+ button:SetSize(31, 31)
+ button:SetFrameLevel(8)
+ button:RegisterForClicks("anyUp")
+ button:RegisterForDrag("LeftButton")
+ button:SetHighlightTexture(136477) --"Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight"
+ local overlay = button:CreateTexture(nil, "OVERLAY")
+ 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 r, g, b = icon:GetVertexColor()
+ icon:SetVertexColor(object.iconR or r, object.iconG or g, object.iconB or b)
+
+ icon.UpdateCoord = updateCoord
+ icon:UpdateCoord()
+
+ button:SetScript("OnEnter", onEnter)
+ button:SetScript("OnLeave", onLeave)
+ button:SetScript("OnClick", onClick)
+ if not db or not db.lock then
+ button:SetScript("OnDragStart", onDragStart)
+ button:SetScript("OnDragStop", onDragStop)
+ end
+ button:SetScript("OnMouseDown", onMouseDown)
+ button:SetScript("OnMouseUp", onMouseUp)
+
+ button.fadeOut = button:CreateAnimationGroup()
+ local animOut = button.fadeOut:CreateAnimation("Alpha")
+ animOut:SetOrder(1)
+ animOut:SetDuration(0.2)
+ animOut:SetFromAlpha(1)
+ animOut:SetToAlpha(0)
+ animOut:SetStartDelay(1)
+ button.fadeOut:SetToFinalAlpha(true)
+
+ lib.objects[name] = button
+
+ if lib.loggedIn then
+ updatePosition(button, db and db.minimapPos)
+ if not db or not db.hide then
+ button:Show()
+ else
+ button:Hide()
+ 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
+-- the icons when checking things like :IsRegistered, which is not necessary.
+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
+
+-- Wait a bit with the initial positioning to let any GetMinimapShape addons
+-- load up.
+if not lib.loggedIn then
+ local f = CreateFrame("Frame")
+ f:SetScript("OnEvent", function(f)
+ for _, button in next, lib.objects do
+ updatePosition(button, button.db and button.db.minimapPos)
+ if not button.db or not button.db.hide then
+ button:Show()
+ else
+ button:Hide()
+ end
+ end
+ lib.loggedIn = true
+ f:SetScript("OnEvent", nil)
+ end)
+ f: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
+
+do
+ local function OnMinimapEnter()
+ if isDraggingButton then return end
+ for _, button in next, lib.objects do
+ if button.showOnMouseover then
+ button.fadeOut:Stop()
+ button:SetAlpha(1)
+ end
+ end
+ end
+ local function OnMinimapLeave()
+ if isDraggingButton then return end
+ for _, button in next, lib.objects do
+ if button.showOnMouseover then
+ button.fadeOut:Play()
+ end
+ end
+ end
+ Minimap:HookScript("OnEnter", OnMinimapEnter)
+ Minimap:HookScript("OnLeave", OnMinimapLeave)
+
+ function lib:ShowOnEnter(name, value)
+ local button = lib.objects[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
+end
+
+function lib:GetButtonList()
+ local t = {}
+ for name in next, lib.objects do
+ t[#t+1] = name
+ end
+ return t
+end
+
+function lib:SetButtonRadius(radius)
+ if type(radius) == "number" then
+ lib.radius = radius
+ for _, button in next, lib.objects do
+ updatePosition(button, button.db and button.db.minimapPos or button.minimapPos)
+ end
+ end
+end
+
+function lib:SetButtonToPosition(button, position)
+ updatePosition(lib.objects[button] or button, position)
+end
+
+-- Upgrade!
+for name, button in next, lib.objects do
+ local db = getDatabase(name)
+ if not db or not db.lock then
+ button:SetScript("OnDragStart", onDragStart)
+ button:SetScript("OnDragStop", onDragStop)
+ end
+ button:SetScript("OnEnter", onEnter)
+ button:SetScript("OnLeave", onLeave)
+ button:SetScript("OnClick", onClick)
+ button:SetScript("OnMouseDown", onMouseDown)
+ button:SetScript("OnMouseUp", onMouseUp)
+
+ if not button.fadeOut then -- Upgrade to 39
+ button.fadeOut = button:CreateAnimationGroup()
+ local animOut = button.fadeOut:CreateAnimation("Alpha")
+ animOut:SetOrder(1)
+ animOut:SetDuration(0.2)
+ animOut:SetFromAlpha(1)
+ animOut:SetToAlpha(0)
+ animOut:SetStartDelay(1)
+ button.fadeOut:SetToFinalAlpha(true)
+ end
+end
+lib:SetButtonRadius(lib.radius) -- Upgrade to 40
diff --git a/Libs/LibDBIcon-1.0/lib.xml b/Libs/LibDBIcon-1.0/lib.xml
new file mode 100644
index 0000000..5dca17c
--- /dev/null
+++ b/Libs/LibDBIcon-1.0/lib.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/Libs/LibDataBroker-1.1/LibDataBroker-1.1.lua b/Libs/LibDataBroker-1.1/LibDataBroker-1.1.lua
new file mode 100644
index 0000000..f47c0cd
--- /dev/null
+++ b/Libs/LibDataBroker-1.1/LibDataBroker-1.1.lua
@@ -0,0 +1,90 @@
+
+assert(LibStub, "LibDataBroker-1.1 requires LibStub")
+assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
+
+local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4)
+if not lib then return end
+oldminor = oldminor or 0
+
+
+lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
+lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
+local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
+
+if oldminor < 2 then
+ lib.domt = {
+ __metatable = "access denied",
+ __index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
+ }
+end
+
+if oldminor < 3 then
+ lib.domt.__newindex = function(self, key, value)
+ if not attributestorage[self] then attributestorage[self] = {} end
+ if attributestorage[self][key] == value then return end
+ attributestorage[self][key] = value
+ local name = namestorage[self]
+ if not name then return end
+ callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
+ callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
+ callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
+ callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
+ end
+end
+
+if oldminor < 2 then
+ function lib:NewDataObject(name, dataobj)
+ if self.proxystorage[name] then return end
+
+ if dataobj then
+ assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
+ self.attributestorage[dataobj] = {}
+ for i,v in pairs(dataobj) do
+ self.attributestorage[dataobj][i] = v
+ dataobj[i] = nil
+ end
+ end
+ dataobj = setmetatable(dataobj or {}, self.domt)
+ self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
+ self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
+ return dataobj
+ end
+end
+
+if oldminor < 1 then
+ function lib:DataObjectIterator()
+ return pairs(self.proxystorage)
+ end
+
+ function lib:GetDataObjectByName(dataobjectname)
+ return self.proxystorage[dataobjectname]
+ end
+
+ function lib:GetNameByDataObject(dataobject)
+ return self.namestorage[dataobject]
+ end
+end
+
+if oldminor < 4 then
+ local next = pairs(attributestorage)
+ function lib:pairs(dataobject_or_name)
+ local t = type(dataobject_or_name)
+ assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)")
+
+ local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
+ assert(attributestorage[dataobj], "Data object not found")
+
+ return next, attributestorage[dataobj], nil
+ end
+
+ local ipairs_iter = ipairs(attributestorage)
+ function lib:ipairs(dataobject_or_name)
+ local t = type(dataobject_or_name)
+ assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)")
+
+ local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
+ assert(attributestorage[dataobj], "Data object not found")
+
+ return ipairs_iter, attributestorage[dataobj], 0
+ end
+end
diff --git a/Libs/LibDataBroker-1.1/README.textile b/Libs/LibDataBroker-1.1/README.textile
new file mode 100644
index 0000000..ef16fed
--- /dev/null
+++ b/Libs/LibDataBroker-1.1/README.textile
@@ -0,0 +1,13 @@
+LibDataBroker is a small WoW addon library designed to provide a "MVC":http://en.wikipedia.org/wiki/Model-view-controller interface for use in various addons.
+LDB's primary goal is to "detach" plugins for TitanPanel and FuBar from the display addon.
+Plugins can provide data into a simple table, and display addons can receive callbacks to refresh their display of this data.
+LDB also provides a place for addons to register "quicklaunch" functions, removing the need for authors to embed many large libraries to create minimap buttons.
+Users who do not wish to be "plagued" by these buttons simply do not install an addon to render them.
+
+Due to it's simple generic design, LDB can be used for any design where you wish to have an addon notified of changes to a table.
+
+h2. Links
+
+* "API documentation":http://github.com/tekkub/libdatabroker-1-1/wikis/api
+* "Data specifications":http://github.com/tekkub/libdatabroker-1-1/wikis/data-specifications
+* "Addons using LDB":http://github.com/tekkub/libdatabroker-1-1/wikis/addons-using-ldb
diff --git a/README.md b/README.md
index 5e14ccb..c139a2e 100644
--- a/README.md
+++ b/README.md
@@ -8,4 +8,27 @@ Intentionally started as a helper addon for a roleplaying friend, Grichelde can
* write out abbreviations for you
* create hilarious moments during roleplay
-
+## FAQ
+
+### How do I start
+
+Grichelde is active right from the start with default mappings. To open the options UI, either left-click on
+the new minimap icon, or type `/gri` or `/grichelde` in the chatbox. All mappings and channels can be configured there.
+
+### My replacement is not taken.
+
+After entering a search or replacement text, you see a button "Okay" next to yout input. This is **not** a validation message,
+but the save button for text. This is a rectriction from the UI library and can be seen in other addons as well.
+Please click on "Okay" button to save the input permanently.
+
+### I get errors, what should I do?
+
+Please report your errors here. Make a screenshot or copy both the error message as well as your recent mappings.
+You can bring up a small windows with your mapping by right-clicking the minimap icon or entering the "/gri mappings" command.
+
+### Why that strange name?
+
+Grichelde is the name of the undead rogue without a jaw, that was played in RP session with my friend.
+She started replacing "s" and "t" letters manually for each line in the chat, which is cumbersome over time.
+(If you wondered how an Undead without a jaw sounds like, its really hilarious.) Without spelling errors,
+"Griselde" in German would be a old-fashioned female first name.
diff --git a/libs.xml b/libs.xml
index 092f800..d8f4fbc 100644
--- a/libs.xml
+++ b/libs.xml
@@ -2,14 +2,16 @@
..\FrameXML\UI.xsd">
+
+
-
-
+
+
diff --git a/localisation/deDE.lua b/localisation/deDE.lua
index ab7c57e..3d96eef 100644
--- a/localisation/deDE.lua
+++ b/localisation/deDE.lua
@@ -9,7 +9,9 @@ L.Upgrade_ToVersion = "Hebe Databank auf Version %s an."
L.Upgrade_Successful = "Upgrade erfolgreich."
L.Debug_Options = "Optionen"
L.Debug_Mappings = "Ersetzungen"
+L.Debug_Mappings_Hint = "Der Inhalt der Textbox dient nur zur Fehlersuche und kann herauskopiert werden. Es werden keine Werte aus dieser Textbox eingelesen oder anderweitig verwertet."
L.Debug_Mappings_Found = "%d Ersetzungen gefunden"
+L.Debug_Profile = "Profil"
-- profiles
L.Profiles_Available = "Verf\195\188gbare Profile:"
@@ -26,6 +28,12 @@ L.Profiles_DeleteError = "Das aktive Profil kann nicht gel\195\182scht werden!"
L.Options_Title = "%s Einstellungen"
L.Options_Enabled_Name = "Aktiv"
L.Options_Enabled_Desc = "Aktiviert %s"
+L.Options_Minimap_Button_Name = "Zeige Minimap-Knopf"
+L.Options_Minimap_Button_Desc = "Zeigt oder versteckt den Knopf an der Miniaturkarte"
+L.Options_Minimap_Tooltip_Options_Left = "Linksklick"
+L.Options_Minimap_Tooltip_Options_Right = "\195\150ffnet oder schlie\195\159t die Einstellungen."
+L.Options_Minimap_Tooltip_Mappings_Left = "Rechtsklick"
+L.Options_Minimap_Tooltip_Mappings_Right = "\195\150ffnet das Debug-Fenster mit Ersetzungscode."
L.Options_Channels_Group_Name = "Kan\195\164le"
L.Options_Channels_Group_Desc = "%s ist in folgenden Kan\195\164len aktiv."
@@ -66,7 +74,7 @@ L.Options_Replacements_DeleteAll_Name = "Alle L\195\182schen"
L.Options_Replacements_DeleteAll_Desc = "L\195\182scht alle Zuweisungen."
L.Options_Replacements_DeleteAll_ConfirmText="Wirklich ALLE Zuweisungen l\195\182schen?"
L.Options_Replacements_Header = "Die Vorkommen links vom Pfeil ( => ) werden in den aktivierten Kan\195\164len gesucht und durch den Text rechts vom Pfeil ersetzt."
- .."|nWird die Gro\195\159- und Kleinschreibung ignoriert, wird die Gro\195\159schreibung jedes Zeichens wird bei der Ersetzung \195\188bernommen."
+ .."|nWird die Gro\195\159- und Kleinschreibung ignoriert, wird die Gro\195\159schreibung jedes Zeichens bei der Ersetzung \195\188bernommen."
.."|nDas Zusammenfassen aufeinanderfolgender Treffer vermeidet unsch\195\182ne Wiederholungen, die durch die Ersetzung entstehen k\195\182nnen."
.."|nMit den beiden Standard-Ersetzung wird so aus \"Tasse\" => \"Ckache\"."
L.Options_Mapping_Group_Name = "%s => %s"
@@ -76,9 +84,9 @@ L.Options_Mapping_SearchText_Name = "Suchtext:"
L.Options_Mapping_SearchText_Desc = "Dieser Text wird in der Chateingabe gesucht."
L.Options_Mapping_ReplaceText_Name = "Ersetzung:"
L.Options_Mapping_ReplaceText_Desc = "Jeder Suchtreffer wird mit diesem Text ersetzt."
-L.Options_Mapping_ExactCase_Name = "exakte Gro\195\159- und Kleinschreibung"
+L.Options_Mapping_ExactCase_Name = "Exakte Gro\195\159- und Kleinschreibung"
L.Options_Mapping_ExactCase_Desc = "Wenn gesetzt, muss die Gro\195\159- und Kleinschreibung des Suchtextes exakt \195\188berein stimmen. Anderfalls wird die Gro\195\159schreibung jedes Zeichens bei der Ersetzung \195\188bernommen."
-L.Options_Mapping_Consolidate_Name = "Fa\195\159e aufeinanderfolgende Treffer zusammen"
+L.Options_Mapping_Consolidate_Name = "Fasse aufeinanderfolgende Treffer zusammen"
L.Options_Mapping_Consolidate_Desc = "Wenn durch die Ersetzung die Zeichenfolge mehrfach hintereinander steht,|nfasse sie zu einem Vorkommen zusammen."
L.Options_Mapping_MoveUp_Name = "^"
L.Options_Mapping_MoveUp_Desc = "nach oben verschieben"
diff --git a/localisation/enUS.lua b/localisation/enUS.lua
index 635fd2f..df570d4 100644
--- a/localisation/enUS.lua
+++ b/localisation/enUS.lua
@@ -7,9 +7,12 @@ L.VersionAbbr = "v"
L.AddonLoaded = "%s now helps you with your spelling disabilities."
L.Upgrade_ToVersion = "Upgrade database to version %s."
L.Upgrade_Successful = "Upgrade successful."
+-- debug
L.Debug_Options = "Options"
L.Debug_Mappings = "Mappings"
-L.Debug_Mappings_Found = "%d Mappings found"
+L.Debug_Mappings_Hint = "The content of this input box is used for debugging purposes only and can be copied. No input from this box will be read or processed."
+L.Debug_Mappings_Found = "%d mappings found"
+L.Debug_Profile = "Profile"
-- profiles
L.Profiles_Available = "Available profiles:"
@@ -26,6 +29,13 @@ L.Profiles_DeleteError = "The active profile cannot be deleted!"
L.Options_Title = "%s Options"
L.Options_Enabled_Name = "Enabled"
L.Options_Enabled_Desc = "Enables %s"
+L.Options_Minimap_Button_Name = "Show minimap button"
+L.Options_Minimap_Button_Desc = "Shows or hides the button on the minimap."
+L.Options_Minimap_Tooltip_Options_Left = "Left-Click"
+L.Options_Minimap_Tooltip_Options_Right = "Opens or closes the options UI."
+L.Options_Minimap_Tooltip_Mappings_Left = "Right-Click"
+L.Options_Minimap_Tooltip_Mappings_Right = "Opens the debug window with mapping code."
+
L.Options_Channels_Group_Name = "Channels"
L.Options_Channels_Group_Desc = "%s is active in the following channels."
diff --git a/twitch/minimap-icon.png b/twitch/minimap-icon.png
new file mode 100644
index 0000000..44f74c3
Binary files /dev/null and b/twitch/minimap-icon.png differ