--[[ |
Name: Sink-2.0 |
Revision: $Rev: 97 $ |
Author(s): Funkydude, Rabbit |
Description: Library that handles chat output. |
Dependencies: LibStub, SharedMedia-3.0 (optional) |
License: CC-BY-NC-SA 3.0 |
]] |
|
--[[ |
Copyright (C) 2008-2013 |
For the attribution bit of the license, as long as you distribute the library unmodified, |
no attribution is required. |
If you derive from the library or change it in any way, you are required to contact the author(s). |
]] |
|
----------------------------------------------------------------------- |
-- Sink-2.0 |
|
local SINK20 = "LibSink-2.0" |
local SINK20_MINOR = 90000 + tonumber(("$Revision: 97 $"):match("(%d+)")) |
|
local sink = LibStub:NewLibrary(SINK20, SINK20_MINOR) |
if not sink then return end |
|
-- Start upgrade |
sink.storageForAddon = sink.storageForAddon or {} |
sink.override = sink.override or {} |
sink.msbt_registered_fonts = sink.msbt_registered_fonts or {} |
sink.registeredScrollAreaFunctions = sink.registeredScrollAreaFunctions or {} |
sink.handlers = sink.handlers or {} |
|
sink.stickyAddons = sink.stickyAddons or { |
Blizzard = true, |
MikSBT = true, |
SCT = true, |
Parrot = true, |
} |
|
-- Upgrade complete |
|
local format = string.format |
|
local L_DEFAULT = "Default" |
local L_DEFAULT_DESC = "Route output from this addon through the first available handler, preferring scrolling combat text addons if available." |
local L_ROUTE = "Route output from this addon through %s." |
local L_SCT = "Scrolling Combat Text" |
local L_MSBT = "MikSBT" |
local L_BIGWIGS = "BigWigs" |
local L_UIERROR = "Blizzard Error Frame" |
local L_CHAT = "Chat" |
local L_BLIZZARD = "Blizzard FCT" |
local L_RW = "Raid Warning" |
local L_PARROT = "Parrot" |
local L_CHANNEL = "Channel" |
local L_OUTPUT = "Output" |
local L_OUTPUT_DESC = "Where to route the output from this addon." |
local L_SCROLL = "Sub section" |
local L_SCROLL_DESC = "Set the sub section where messages should appear.\n\nOnly available for some output sinks." |
local L_STICKY = "Sticky" |
local L_STICKY_DESC = "Set messages from this addon to appear as sticky.\n\nOnly available for some output sinks." |
local L_NONE = "None" |
local L_NONE_DESC = "Hide all messages from this addon." |
local L_NOTINCHANNEL = " (You tried sending this to the channel %s, but it appears you are not there.)" |
|
local l = GetLocale() |
if l == "koKR" then |
L_DEFAULT = "기본" |
L_DEFAULT_DESC = "ì²ìì¼ë¡ ì¬ì© ê°ë¥í í¸ë ì´ë를 íµí´ ì´ ì ëì¨ì¼ë¡ë¶í° ì¶ë ¥ì ë³´ë
ëë¤." |
L_ROUTE = "%s|1ì;를; íµí´ ì´ ì ëì¨ì ë©ìì§ë¥¼ ì¶ë ¥í©ëë¤." |
L_SCT = "Scrolling Combat Text" |
L_MSBT = "MikSBT" |
L_BIGWIGS = "BigWigs" |
L_UIERROR = "ë¸ë¦¬ìë ì¤ë¥ ì°½" |
L_CHAT = "ëíì°½" |
L_BLIZZARD = "ë¸ë¦¬ìë FCT" |
L_RW = "공격ë 경보" |
L_PARROT = "Parrot" |
L_OUTPUT = "ì¶ë ¥" |
L_OUTPUT_DESC = "ì´ëì ì´ ì ëì¨ì ë©ìì§ë¥¼ ì¶ë ¥í ì§ ì íí©ëë¤." |
L_SCROLL = "ì¤í¬ë¡¤ ìì" |
L_SCROLL_DESC = "ë©ìì§ë¥¼ ì¶ë ¥í ì¤í¬ë£° ììì ì¤ì í©ëë¤.\n\nParrot, SCTë MikSBTë§ ì¬ì© ê°ë¥í©ëë¤." |
L_STICKY = "ì ì°©" |
L_STICKY_DESC = "ë¬ë¼ë¶ë ê²ì²ë¼ ë³´ì¼ ì´ ì ëì¨ì ë©ìì§ë¥¼ ì¤ì í©ëë¤.\n\në¸ë¦¬ìë FCT, Parrot, SCTë MikSBTë§ ì¬ì© ê°ë¥í©ëë¤." |
L_NONE = "ìì" |
L_NONE_DESC = "ì´ ì ëì¨ì 모ë ë©ìì§ë¥¼ ì¨ê¹ëë¤." |
elseif l == "frFR" then |
L_DEFAULT = "Par défaut" |
L_DEFAULT_DESC = "Transmet la sortie de cet addon via le premier handler disponible, de préférence les textes de combat défilants s'il y en a." |
L_ROUTE = "Transmet la sortie de cet addon via %s." |
L_SCT = "Scrolling Combat Text" |
L_MSBT = "MikSBT" |
L_BIGWIGS = "BigWigs" |
L_UIERROR = "Cadre des erreurs" |
L_CHAT = "Fenêtre de discussion" |
L_BLIZZARD = "TCF de Blizzard" |
L_RW = "Avertissement raid" |
L_PARROT = "Parrot" |
L_CHANNEL = "Canal" |
L_OUTPUT = "Sortie" |
L_OUTPUT_DESC = "Destination de la sortie de cet addon." |
L_SCROLL = "Sous-section" |
L_SCROLL_DESC = "Définit la sous-section où les messages doivent apparaitre.\n\nDisponible uniquement dans certains cas." |
L_STICKY = "En évidence" |
L_STICKY_DESC = "Fait en sortie que les messages de cet addon apparaissent en évidence.\n\nDisponible uniquement dans certains cas." |
L_NONE = "Aucun" |
L_NONE_DESC = "Masque tous les messages provenant de cet addon." |
elseif l == "deDE" then |
L_DEFAULT = "Voreinstellung" |
L_DEFAULT_DESC = "Leitet die Ausgabe von diesem Addon zum ersten verfügbaren Ausgabeort, vorzugsweise Scrollende Kampf Text Addons wenn verfügbar." |
L_ROUTE = "Schickt die Meldungen dieses Addons an %s." |
L_SCT = "Scrolling Combat Text(SCT)" |
L_MSBT = "MikSBT" |
L_BIGWIGS = "BigWigs" |
L_UIERROR = "Blizzard's Fehler Fenster" |
L_CHAT = "Im Chat" |
L_BLIZZARD = "Blizzard's schwebenden Kampftext" |
L_RW = "Schlachtzug's Warnung" |
L_PARROT = "Parrot" |
L_OUTPUT = "Ausgabe" |
L_OUTPUT_DESC = "Wohin die Meldungen des Addons gesendet werden soll." |
L_SCROLL = "Scroll Bereich" |
L_SCROLL_DESC = "Setzt die Scroll Bereich, wo die Meldungen erscheinen sollen.\n\nNur verfügbar für Parrot, SCT oder MikSBT." |
L_STICKY = "Stehend" |
L_STICKY_DESC = "LäÃt Nachrichten von diesem Addon als stehende Nachrichten erscheinen.\n\nNur verfügbar für Blizzard FCT, Parrot, SCT oder MikSBT." |
L_NONE = "Nirgends" |
L_NONE_DESC = "Versteckt alle Meldungen von diesem Addon." |
elseif l == "zhCN" then |
L_DEFAULT = "é»è®¤" |
L_DEFAULT_DESC = "æ件çè¾åºæ¹å¼åå³äºç¬¬ä¸ä¸ªå¯ç¨æ件ï¼ä¾å¦æ SCT æ件ï¼åä¼å
使ç¨ã" |
L_ROUTE = "ç»ç±%sæ¾ç¤ºä¿¡æ¯ã" |
L_SCT = "SCT" |
L_MSBT = "MikSBT" |
L_BIGWIGS = "BigWigs" |
L_UIERROR = "Blizzard é误æ¡ä½" |
L_CHAT = "è天æ¡ä½" |
L_BLIZZARD = "ç³»ç»èªå¸¦æ»å¨ææä¿¡æ¯" |
L_RW = "å¢éè¦å" |
L_PARROT = "Parrot" |
L_CHANNEL = "é¢é" |
L_OUTPUT = "è¾åºæ¨¡å¼" |
L_OUTPUT_DESC = "设置æ¾ç¤ºä½ç½®ã" |
L_SCROLL = "æ»å¨åºå" |
L_SCROLL_DESC = "设置æ»å¨ä¿¡æ¯æ¾ç¤ºä½ç½®ã\n\nåªæ ParrotãSCT å MikSBT æ¯æã" |
L_STICKY = "åºå®" |
L_STICKY_DESC = "设置信æ¯åºå®æ¾ç¤ºä½ç½®ã\n\nåªæç³»ç»èªå¸¦æ»å¨ææä¿¡æ¯ãParrotãSCT å MikSBT æ¯æã" |
L_NONE = "éè" |
L_NONE_DESC = "éèæææ¥èªæ件çä¿¡æ¯ã" |
L_NOTINCHANNEL = "ï¼å°è¯åéå°%sé¢éï¼ä½å
¶å¹¶ä¸åå¨ãï¼" |
elseif l == "zhTW" then |
L_DEFAULT = "é è¨" |
L_DEFAULT_DESC = "æ件輸åºç¶ç±ç¬¬ä¸åå¯ä½¿ç¨çèçå¨é¡¯ç¤ºï¼å¦ææ SCT ç話ï¼ååªå
使ç¨ã" |
L_ROUTE = "æ件輸åºç¶ç±%s顯示ã" |
L_SCT = "SCT" |
L_MSBT = "MikSBT" |
L_BIGWIGS = "BigWigs" |
L_UIERROR = "Blizzard é¯èª¤è¨æ¯æ¡æ¶" |
L_CHAT = "è天è¦çª" |
L_BLIZZARD = "Blizzard æµ®åæ°é¬¥æå" |
L_RW = "åéè¦å" |
L_PARROT = "Parrot" |
L_CHANNEL = "é »é" |
L_OUTPUT = "顯示模å¼" |
L_OUTPUT_DESC = "æ件輸åºç¶ç±åªè£¡é¡¯ç¤ºã" |
L_SCROLL = "滾ååå" |
L_SCROLL_DESC = "è¨å®æ»¾åè¨æ¯åºç¾ä½ç½®ã\n\nåªæ Parrotï¼SCT å MikSBT ææ¯æ´ã" |
L_STICKY = "åºå®" |
L_STICKY_DESC = "è¨å®ä½¿ç¨åºå®è¨æ¯ã\n\nåªæ Blizzard æµ®åæ°é¬¥æåï¼Parrotï¼SCT å MikSBT ææ¯æ´ã" |
L_NONE = "é±è" |
L_NONE_DESC = "é±èæææ件輸åºã" |
L_NOTINCHANNEL = "ï¼ä½ å試ç¼éè¨æ¯å°é »é%sï¼ä½æ¯æ¤é »éä¸åå¨ãï¼" |
elseif l == "ruRU" then |
L_DEFAULT = "Ðо ÑмолÑаниÑ" |
L_DEFAULT_DESC = "ÐаÑÑÑÑÑ Ð²Ñвода ÑообÑений данного аддона ÑеÑез пеÑвое доÑÑÑпное ÑÑÑÑойÑÑво, пÑедпоÑиÑÐ°Ñ Ð´Ð¾ÑÑÑпнÑе Ð°Ð´Ð´Ð¾Ð½Ñ Ð¿ÑокÑÑÑки ÑекÑÑа боÑ." |
L_ROUTE = "ÐаÑÑÑÑÑ Ð²Ñвода ÑообÑений данного аддона ÑеÑез %s." |
L_SCT = "SCT" |
L_MSBT = "MikSBT" |
L_BIGWIGS = "BigWigs" |
L_UIERROR = "ФÑейм оÑибок Blizzard" |
L_CHAT = "ЧаÑ" |
L_BLIZZARD = "Blizzard FCT" |
L_RW = "ÐбÑÑвление ÑейдÑ" |
L_PARROT = "Parrot" |
L_CHANNEL = "Ðанал" |
L_OUTPUT = "ÐÑвод" |
L_OUTPUT_DESC = "ÐÑда вÑводиÑÑ ÑообÑÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ аддона." |
L_SCROLL = "ÐблаÑÑÑ Ð¿ÑокÑÑÑки" |
L_SCROLL_DESC = "ÐазнаÑиÑÑ Ð¾Ð±Ð»Ð°ÑÑÑ Ð¿ÑокÑÑÑки кÑда Ð´Ð¾Ð»Ð¶Ð½Ñ Ð²ÑводиÑÑÑÑ ÑообÑениÑ.\n\nÐоÑÑÑпно ÑолÑко Ð´Ð»Ñ Parrotа, SCT или MikSBT." |
L_STICKY = "Ðлейкий" |
L_STICKY_DESC = "СделаÑÑ ÑообÑÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ аддона клейкими.\n\nÐоÑÑÑпно ÑолÑко Ð´Ð»Ñ Blizzard FCT, Parrot, SCT или MikSBT." |
L_NONE = "ÐеÑÑ" |
L_NONE_DESC = "СкÑÑÑÑ Ð²Ñе ÑообÑÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ аддона." |
elseif l == "esES" or l == "esMX" then |
L_DEFAULT = "Por defecto" |
L_DEFAULT_DESC = "EnvÃa los mensajes de este addon al primer canal disponible, preferiblemente a addons SCT si los hay." |
L_ROUTE = "EnvÃa los mensajes de este addon a %s." |
L_SCT = "Scrolling Combat Text" |
L_MSBT = "MikSBT" |
L_BIGWIGS = "BigWigs" |
L_UIERROR = "Marco de errores de Blizzard" |
L_CHAT = "Chat" |
L_BLIZZARD = "Texto flotante de Blizzard" |
L_RW = "Aviso de la banda" |
L_PARROT = "Parrot" |
L_CHANNEL = "Canal especÃfico" |
L_OUTPUT = "Salida" |
L_OUTPUT_DESC = "Dónde enviar los mensajes de este addon." |
L_SCROLL = "Sub seción" |
L_SCROLL_DESC = "Especifica dónde deberán mostrarse los mensajes.\n\nSólo disponible en algunas opciones de salida." |
L_STICKY = "Destacar" |
L_STICKY_DESC = "Especifica que los mensajes deberán mostrarse de forma destacada.\n\nSólo disponible en algunas opciones de salida." |
L_NONE = "Ninguno" |
L_NONE_DESC = "Oculta todos los mensajes de este addon." |
elseif l == "ptBR" then |
-- Missing |
elseif l == "itIT" then |
-- Missing |
end |
|
local SML = LibStub("LibSharedMedia-3.0", true) |
|
local function getSticky(addon) |
return sink.storageForAddon[addon] and sink.storageForAddon[addon].sink20Sticky or nil |
end |
|
-- Thanks to Antiarc and his Soar-1.0 library for most of the 'meat' of the |
-- sink-specific functions. |
|
local function parrot(addon, text, r, g, b, font, size, outline, sticky, loc, icon) |
local location = sink.storageForAddon[addon] and sink.storageForAddon[addon].sink20ScrollArea or "Notification" |
local s = getSticky(addon) or sticky |
Parrot:ShowMessage(text, location, s, r, g, b, font, size, outline, icon) |
end |
|
local sct_color = {} |
local function sct(addon, text, r, g, b, font, size, outline, sticky, _, icon) |
sct_color.r, sct_color.g, sct_color.b = r, g, b |
local loc = sink.storageForAddon[addon] and sink.storageForAddon[addon].sink20ScrollArea or "Messages" |
local location = (loc == "Outgoing" and SCT.FRAME1) or (loc == "Incoming" and SCT.FRAME2) or SCT.MSG |
local s = getSticky(addon) or sticky |
SCT:DisplayCustomEvent(text, sct_color, s, location, nil, icon) |
end |
|
local msbt_outlines = {["NORMAL"] = 1, ["OUTLINE"] = 2, ["THICKOUTLINE"] = 3} |
local function msbt(addon, text, r, g, b, font, size, outline, sticky, _, icon) |
if font and SML and not sink.msbt_registered_fonts[font] then |
MikSBT.RegisterFont(font, SML:Fetch("font", font)) |
sink.msbt_registered_fonts[font] = true |
end |
local location = sink.storageForAddon[addon] and sink.storageForAddon[addon].sink20ScrollArea or MikSBT.DISPLAYTYPE_NOTIFICATION |
local s = getSticky(addon) or sticky |
MikSBT.DisplayMessage(text, location, s, r * 255, g * 255, b * 255, size, font, msbt_outlines[outline], icon) |
end |
|
local function blizzard(addon, text, r, g, b, font, size, outline, sticky, _, icon) |
if icon then text = "|T"..icon..":20:20:-5|t"..text end |
if tostring(SHOW_COMBAT_TEXT) ~= "0" then |
local s = getSticky(addon) or sticky |
if type(CombatText_AddMessage) == "nil" then |
UIParentLoadAddOn("Blizzard_CombatText") |
end |
CombatText_AddMessage(text, CombatText_StandardScroll, r, g, b, s and "crit" or nil, false) |
else |
UIErrorsFrame:AddMessage(text, r, g, b, 1.0) |
end |
end |
|
sink.channelMapping = sink.channelMapping or { |
[SAY] = "SAY", |
[PARTY] = "PARTY", |
[INSTANCE_CHAT] = "INSTANCE_CHAT", |
[GUILD_CHAT] = "GUILD", |
[OFFICER_CHAT] = "OFFICER", |
[YELL] = "YELL", |
[RAID] = "RAID", |
[RAID_WARNING] = "RAID_WARNING", |
[GROUP] = "GROUP", |
} |
sink.channelMappingIds = sink.channelMappingIds or {} |
sink.frame = sink.frame or CreateFrame("Frame") |
sink.frame:UnregisterAllEvents() |
sink.frame:RegisterEvent("CHANNEL_UI_UPDATE") |
sink.frame:RegisterEvent("PLAYER_ENTERING_WORLD") |
do |
local function loop(...) |
wipe(sink.channelMappingIds) |
for i = 1, select("#", ...), 2 do |
local id, name = select(i, ...) |
sink.channelMappingIds[name] = id |
end |
for k, v in next, sink.channelMapping do |
if v == "CHANNEL" and not sink.channelMappingIds[k] then |
sink.channelMapping[k] = nil |
end |
end |
for k in next, sink.channelMappingIds do sink.channelMapping[k] = "CHANNEL" end |
end |
local function rescanChannels() loop(GetChannelList()) end |
sink.frame:SetScript("OnEvent", rescanChannels) |
rescanChannels() |
end |
|
local function color_strip(a, b, c) |
if b:sub(1,2) == "|H" then |
return a..b..c |
else |
return b |
end |
end |
|
local function channel(addon, text) |
-- Sanitize the text, remove all color codes. |
text = text:gsub("(|c%x%x%x%x%x%x%x%x)(.-)(|r)", color_strip) |
local loc = sink.storageForAddon[addon] and sink.storageForAddon[addon].sink20ScrollArea or "SAY" |
local chan = sink.channelMapping[loc] |
if chan == "GROUP" then |
chan = (IsInGroup(2) and "INSTANCE_CHAT") or (IsInRaid() and "RAID") or (IsInGroup() and "PARTY") or "SAY" |
elseif chan == "CHANNEL" then |
local id, name = GetChannelName(sink.channelMappingIds[loc]) |
if name then |
SendChatMessage(text, "CHANNEL", nil, id) |
else |
print("LibSink:", text, L_NOTINCHANNEL:format(loc)) |
end |
return |
end |
SendChatMessage(text, chan or "SAY") |
end |
|
local function chat(addon, text, r, g, b, _, _, _, _, _, icon) |
if icon then text = "|T"..icon..":15|t"..text end |
DEFAULT_CHAT_FRAME:AddMessage(text, r, g, b) |
end |
|
local function uierror(addon, text, r, g, b, _, _, _, _, _, icon) |
if icon then text = "|T"..icon..":20:20:-5|t"..text end |
UIErrorsFrame:AddMessage(text, r, g, b, 1.0) |
end |
|
local rw |
do |
local white = {r = 1, g = 1, b = 1} |
function rw(addon, text, r, g, b, _, _, _, _, _, icon) |
if r or g or b then |
text = format("\124cff%02x%02x%02x%s\124r", (r or 0) * 255, (g or 0) * 255, (b or 0) * 255, text) |
end |
if icon then text = "\124T"..icon..":20:20:-5\124t"..text end |
RaidNotice_AddMessage(RaidWarningFrame, text, white) |
end |
end |
|
local function noop() --[[ noop! ]] end |
|
local handlerPriority = { "Parrot", "SCT", "MikSBT" } |
local customHandlersEnabled = { |
Parrot = function() |
if not _G.Parrot then return end |
return _G.Parrot.IsEnabled and _G.Parrot:IsEnabled() or _G.Parrot:IsActive() |
end, |
SCT = function() |
return _G.SCT and _G.SCT:IsEnabled() |
end, |
MikSBT = function() |
return _G.MikSBT and not _G.MikSBT.IsModDisabled() |
end, |
} |
|
local currentHandler = nil |
local function getPrioritizedSink() |
if currentHandler then |
local check = customHandlersEnabled[currentHandler] |
if check and check() then |
return sink.handlers[currentHandler] |
end |
end |
for i, v in next, handlerPriority do |
local check = customHandlersEnabled[v] |
if check and check() then |
currentHandler = v |
return sink.handlers[v] |
end |
end |
if SHOW_COMBAT_TEXT and tostring(SHOW_COMBAT_TEXT) ~= "0" then |
return blizzard |
end |
return chat |
end |
|
local function pour(addon, text, r, g, b, ...) |
local func = sink.override and sink.handlers[sink.override] or nil |
if not func and sink.storageForAddon[addon] and sink.storageForAddon[addon].sink20OutputSink then |
local h = sink.storageForAddon[addon].sink20OutputSink |
func = sink.handlers[h] |
-- If this sink is not available now, find one manually. |
if customHandlersEnabled[h] and not customHandlersEnabled[h]() then |
func = nil |
end |
end |
if not func then |
func = getPrioritizedSink() |
end |
if not func then func = chat end |
func(addon, text, r or 1, g or 1, b or 1, ...) |
end |
|
function sink:Pour(textOrAddon, ...) |
local t = type(textOrAddon) |
if t == "string" then |
pour(self, textOrAddon, ...) |
elseif t == "number" then |
pour(self, tostring(textOrAddon), ...) |
elseif t == "table" then |
pour(textOrAddon, ...) |
else |
error("Invalid argument 2 to :Pour, must be either a string or a table.") |
end |
end |
|
local sinks |
do |
-- Maybe we want to hide them instead of disable |
local function shouldDisableSCT() |
return not _G.SCT |
end |
local function shouldDisableMSBT() |
return not _G.MikSBT |
end |
local function shouldDisableParrot() |
return not _G.Parrot |
end |
local function shouldDisableFCT() |
return not SHOW_COMBAT_TEXT or tostring(SHOW_COMBAT_TEXT) == "0" |
end |
|
local sctFrames = {"Incoming", "Outgoing", "Messages"} |
local msbtFrames = nil |
local tmp = {} |
local function getScrollAreasForAddon(addon) |
if type(addon) ~= "string" then return nil end |
if addon == "Parrot" then |
if Parrot.GetScrollAreasChoices then |
return Parrot:GetScrollAreasChoices() |
else |
return Parrot:GetScrollAreasValidate() |
end |
elseif addon == "MikSBT" then |
if not msbtFrames then |
msbtFrames = {} |
for key, name in MikSBT.IterateScrollAreas() do |
msbtFrames[#msbtFrames+1] = name |
end |
end |
return msbtFrames |
elseif addon == "SCT" then |
return sctFrames |
elseif addon == "Channel" then |
wipe(tmp) |
for k in next, sink.channelMapping do |
tmp[#tmp + 1] = k |
end |
return tmp |
elseif sink.registeredScrollAreaFunctions[addon] then |
return sink.registeredScrollAreaFunctions[addon]() |
end |
return nil |
end |
|
local emptyTable, args, options = {}, {}, {} |
sinks = { |
Default = {L_DEFAULT, L_DEFAULT_DESC}, |
SCT = {L_SCT, nil, shouldDisableSCT}, |
MikSBT = {L_MSBT, nil, shouldDisableMSBT}, |
Parrot = {L_PARROT, nil, shouldDisableParrot}, |
Blizzard = {L_BLIZZARD, nil, shouldDisableFCT}, |
RaidWarning = {L_RW}, |
ChatFrame = {L_CHAT}, |
Channel = {L_CHANNEL}, |
UIErrorsFrame = {L_UIERROR}, |
None = {L_NONE, L_NONE_DESC} |
} |
|
local function getAce2SinkOptions(key, opts) |
local name, desc, hidden = unpack(opts) |
args["Ace2"][key] = { |
type = "toggle", |
name = name, |
desc = desc or format(L_ROUTE, name), |
isRadio = true, |
hidden = hidden |
} |
end |
|
function sink.GetSinkAce2OptionsDataTable(addon) |
options["Ace2"][addon] = options["Ace2"][addon] or { |
output = { |
type = "group", |
name = L_OUTPUT, |
desc = L_OUTPUT_DESC, |
pass = true, |
get = function(key) |
if not sink.storageForAddon[addon] then |
return "Default" |
end |
if tostring(key) == "nil" then |
-- Means AceConsole wants to list the output option, |
-- so we should show which sink is currently used. |
return sink.storageForAddon[addon].sink20OutputSink or L_DEFAULT |
end |
if key == "ScrollArea" then |
return sink.storageForAddon[addon].sink20ScrollArea |
elseif key == "Sticky" then |
return sink.storageForAddon[addon].sink20Sticky |
else |
if sink.storageForAddon[addon].sink20OutputSink == key then |
local sa = getScrollAreasForAddon(key) |
options["Ace2"][addon].output.args.ScrollArea.validate = sa or emptyTable |
options["Ace2"][addon].output.args.ScrollArea.disabled = not sa |
options["Ace2"][addon].output.args.Sticky.disabled = not sink.stickyAddons[key] |
end |
return sink.storageForAddon[addon].sink20OutputSink and sink.storageForAddon[addon].sink20OutputSink == key or nil |
end |
end, |
set = function(key, value) |
if not sink.storageForAddon[addon] then return end |
if key == "ScrollArea" then |
sink.storageForAddon[addon].sink20ScrollArea = value |
elseif key == "Sticky" then |
sink.storageForAddon[addon].sink20Sticky = value |
elseif value then |
local sa = getScrollAreasForAddon(key) |
options["Ace2"][addon].output.args.ScrollArea.validate = sa or emptyTable |
options["Ace2"][addon].output.args.ScrollArea.disabled = not sa |
options["Ace2"][addon].output.args.Sticky.disabled = not sink.stickyAddons[key] |
sink.storageForAddon[addon].sink20OutputSink = key |
end |
end, |
args = args["Ace2"], |
disabled = function() |
return (type(addon.IsActive) == "function" and not addon:IsActive()) or nil |
end |
} |
} |
return options["Ace2"][addon] |
end |
|
-- Ace3 options data table format |
local function getAce3SinkOptions(key, opts) |
local name, desc, hidden = unpack(opts) |
args["Ace3"][key] = { |
type = "toggle", |
name = name, |
desc = desc or format(L_ROUTE, name), |
hidden = hidden |
} |
end |
|
function sink.GetSinkAce3OptionsDataTable(addon) |
if not options["Ace3"][addon] then |
options["Ace3"][addon] = { |
type = "group", |
name = L_OUTPUT, |
desc = L_OUTPUT_DESC, |
args = args["Ace3"], |
get = function(info) |
local key = info[#info] |
if not sink.storageForAddon[addon] then |
return "Default" |
end |
if tostring(key) == "nil" then |
-- Means AceConsole wants to list the output option, |
-- so we should show which sink is currently used. |
return sink.storageForAddon[addon].sink20OutputSink or L_DEFAULT |
end |
if key == "ScrollArea" then |
return sink.storageForAddon[addon].sink20ScrollArea |
elseif key == "Sticky" then |
return sink.storageForAddon[addon].sink20Sticky |
else |
if sink.storageForAddon[addon].sink20OutputSink == key then |
local sa = getScrollAreasForAddon(key) |
if sa then |
for k,v in ipairs(sa) do |
sa[k] = nil |
sa[v] = v |
end |
end |
options["Ace3"][addon].args.ScrollArea.values = sa or emptyTable |
options["Ace3"][addon].args.ScrollArea.disabled = not sa |
options["Ace3"][addon].args.Sticky.disabled = not sink.stickyAddons[key] |
end |
return sink.storageForAddon[addon].sink20OutputSink and sink.storageForAddon[addon].sink20OutputSink == key or nil |
end |
end, |
set = function(info, v) |
local key = info[#info] |
if not sink.storageForAddon[addon] then return end |
if key == "ScrollArea" then |
sink.storageForAddon[addon].sink20ScrollArea = v |
elseif key == "Sticky" then |
sink.storageForAddon[addon].sink20Sticky = v |
elseif v then |
local sa = getScrollAreasForAddon(key) |
if sa then |
for k,v in ipairs(sa) do |
sa[k] = nil |
sa[v] = v |
end |
end |
options["Ace3"][addon].args.ScrollArea.values = sa or emptyTable |
options["Ace3"][addon].args.ScrollArea.disabled = not sa |
options["Ace3"][addon].args.Sticky.disabled = not sink.stickyAddons[key] |
sink.storageForAddon[addon].sink20OutputSink = key |
end |
end, |
disabled = function() |
return (type(addon.IsEnabled) == "function" and not addon:IsEnabled()) or nil |
end, |
} |
end |
return options["Ace3"][addon] |
end |
|
local sinkOptionGenerators = { |
["Ace2"] = getAce2SinkOptions, |
["Ace3"] = getAce3SinkOptions |
} |
for generatorName, generator in next, sinkOptionGenerators do |
options[generatorName] = options[generatorName] or {} |
args[generatorName] = args[generatorName] or {} |
for name, opts in next, sinks do |
generator(name, opts) |
end |
end |
|
args["Ace2"].ScrollArea = { |
type = "text", |
name = L_SCROLL, |
desc = L_SCROLL_DESC, |
validate = emptyTable, |
order = -1, |
disabled = true |
} |
args["Ace2"].Sticky = { |
type = "toggle", |
name = L_STICKY, |
desc = L_STICKY_DESC, |
validate = emptyTable, |
order = -2, |
disabled = true |
} |
|
args["Ace3"].ScrollArea = { |
type = "select", |
name = L_SCROLL, |
desc = L_SCROLL_DESC, |
values = emptyTable, |
order = -1, |
disabled = true |
} |
args["Ace3"].Sticky = { |
type = "toggle", |
name = L_STICKY, |
desc = L_STICKY_DESC, |
order = -2, |
disabled = true |
} |
|
function sink:RegisterSink(shortName, name, desc, func, scrollAreaFunc, hasSticky) |
assert(type(shortName) == "string") |
assert(type(name) == "string") |
assert(type(desc) == "string" or desc == nil) |
assert(type(func) == "function" or type(func) == "string") |
assert(type(scrollAreaFunc) == "function" or scrollAreaFunc == nil) |
assert(type(hasSticky) == "boolean" or hasSticky == nil) |
|
if sinks[shortName] or sink.handlers[shortName] then |
error("There's already a sink by the short name %q.", shortName) |
end |
sinks[shortName] = {name, desc} |
-- Save it for library upgrades. |
if not sink.registeredSinks then sink.registeredSinks = {} end |
sink.registeredSinks[shortName] = sinks[shortName] |
|
if type(func) == "function" then |
sink.handlers[shortName] = func |
else |
sink.handlers[shortName] = function(...) |
self[func](self, ...) |
end |
end |
if type(scrollAreaFunc) == "function" then |
sink.registeredScrollAreaFunctions[shortName] = scrollAreaFunc |
elseif type(scrollAreaFunc) == "string" then |
sink.registeredScrollAreaFunctions[shortName] = function(...) |
return self[scrollAreaFunc](self, ...) |
end |
end |
sink.stickyAddons[shortName] = hasSticky and true or nil |
|
for k, v in next, sinkOptionGenerators do |
v(shortName, sinks[shortName]) |
end |
end |
end |
|
function sink.SetSinkStorage(addon, storage) |
assert(type(addon) == "table") |
assert(type(storage) == "table", "Storage must be a table") |
sink.storageForAddon[addon] = storage |
end |
|
-- Sets a sink override for -all- addons, librarywide. |
function sink:SetSinkOverride(override) |
assert(type(override) == "string" or override == nil) |
if override and not sink.handlers[override] then |
error("There's no %q sink.", override) |
end |
sink.override = override |
end |
|
-- Put this at the bottom, because we need the local functions to exist first. |
local handlers = { |
Parrot = parrot, |
SCT = sct, |
MikSBT = msbt, |
ChatFrame = chat, |
Channel = channel, |
UIErrorsFrame = uierror, |
Blizzard = blizzard, |
RaidWarning = rw, |
None = noop, |
} |
-- Overwrite any handler functions from the old library |
for k, v in next, handlers do |
sink.handlers[k] = v |
end |
|
----------------------------------------------------------------------- |
-- Embed handling |
|
sink.embeds = sink.embeds or {} |
|
local mixins = { |
"Pour", "RegisterSink", "SetSinkStorage", |
"GetSinkAce2OptionsDataTable", "GetSinkAce3OptionsDataTable" |
} |
|
function sink:Embed(target) |
sink.embeds[target] = true |
for _,v in next, mixins do |
target[v] = sink[v] |
end |
return target |
end |
|
for addon in next, sink.embeds do |
sink:Embed(addon) |
end |
|