--@curseforge-project-slug: libsink-2-0@
-----------------------------------------------------------------------
-- Sink-2.0
local SINK20 = " LibSink-2.0 "
local SINK20_MINOR = 110002
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 ,
}
-- Upgrade complete
local _G = _G
local format , gsub , wipe , next , select = string.format , string.gsub , table.wipe , next , select
local IsInRaid , IsInGroup , SendChatMessage = IsInRaid , IsInGroup , SendChatMessage
-- Make sure FCT is loaded
local EnableAddOn = C_AddOns.EnableAddOn
local IsAddOnLoaded = C_AddOns.IsAddOnLoaded
local LoadAddOn = C_AddOns.LoadAddOn
EnableAddOn ( " Blizzard_CombatText " )
local loadFCT = nil
if not IsAddOnLoaded ( " Blizzard_CombatText " ) then
loadFCT = function ( )
loadFCT = nil
LoadAddOn ( " Blizzard_CombatText " )
end
end
local L = { }
L.DEFAULT = " Default "
L.CHAT = " Chat "
L.NONE = " None "
L.RW = " Raid Warning "
L.BLIZZARD = " Floating Combat Text "
L.CHANNEL = " Channel "
L.SAY = " Say "
L.PARTY = " Party "
L.INSTANCE_CHAT = " Instance "
L.GUILD_CHAT = " Guild Chat "
L.OFFICER_CHAT = " Officer Chat "
L.YELL = " Yell "
L.RAID = " Raid "
L.RAID_WARNING = " Raid Warning "
L.GROUP = " Group "
L.DEFAULT_DESC = " Route output from this addon through the first available handler, preferring scrolling combat text addons if available. "
L.ROUTE = " Route output from this addon through %s. "
L.UIERROR = " Blizzard Error Frame "
L.OUTPUT = " Output "
L.OUTPUT_DESC = " Where to route the output from this addon. "
L.SCROLL = " Sub section "
L.SCROLL_DESC = " Set the sub section where messages should appear. \n \n Only available for some outputs. "
L.STICKY = " Sticky "
L.STICKY_DESC = " Set messages from this addon to appear as sticky. \n \n Only available for some outputs. "
L.NONE_DESC = " Hide all messages from this addon. "
L.NOTINCHANNEL = " LibSink: %s (Sending to channel '%s' failed, you're not in it) "
do
local l = GetLocale ( )
if l == " koKR " then
L.DEFAULT = " 기본 "
L.CHAT = " 대화 "
L.NONE = " 없음 "
L.RW = " 공격대 경보 "
L.BLIZZARD = " 전투 상황 알림 "
L.CHANNEL = " 채널 "
L.SAY = " 일반 대화 "
L.PARTY = " 파티 "
L.INSTANCE_CHAT = " 인스턴스 "
L.GUILD_CHAT = " 길드 대화 "
L.OFFICER_CHAT = " 길드관리자 대화 "
L.YELL = " 외침 "
L.RAID = " 공격대 "
L.RAID_WARNING = " 공격대 경보 "
L.GROUP = " 파티 "
L [ " DEFAULT_DESC " ] = " 처음으로 사용 가능한 트레이너를 통해 이 애드온으로부터 출력을 보냅니다. " -- Needs review
L [ " NONE_DESC " ] = " 이 애드온의 모든 메시지를 숨김니다. " -- Needs review
L [ " NOTINCHANNEL " ] = " LibSink: %s (%s 채널로 전송 실패) " -- Needs review
L [ " OUTPUT " ] = " 출력 " -- Needs review
L [ " OUTPUT_DESC " ] = " 어디에 이 애드온의 메시지를 출력할지 선택합니다. " -- Needs review
L [ " ROUTE " ] = " %s|1을;를; 통해 이 애드온의 메시지를 출력합니다. " -- Needs review
L [ " SCROLL " ] = " 스크롤 영역 " -- Needs review
L [ " SCROLL_DESC " ] = " 메시지를 출력할 스크룰 영역을 설정합니다. " -- Needs review
L [ " STICKY " ] = " 점착 " -- Needs review
L [ " STICKY_DESC " ] = " 달라붙는 것처럼 보일 이 애드온의 메시지를 설정합니다. " -- Needs review
L [ " UIERROR " ] = " 블리자드 오류 창 " -- Needs review
elseif l == " frFR " then
L.DEFAULT = " Défaut "
L.CHAT = " Discussion "
L.NONE = " Aucun "
L.RW = " Avertissement Raid "
L.BLIZZARD = " Texte de combat flottant "
L.CHANNEL = " Canal "
L.SAY = " Dire "
L.PARTY = " Groupe "
L.INSTANCE_CHAT = " Instance "
L.GUILD_CHAT = " Guilde "
L.OFFICER_CHAT = " Officier "
L.YELL = " Crier "
L.RAID = " Raid "
L.RAID_WARNING = " Avertissement Raid "
L.GROUP = " Groupe "
L [ " DEFAULT_DESC " ] = " Dirige la sortie de cet addon vers le premier gestionnaire disponible, de préférence les addons de texte de combat flottant si disponibles. " -- Needs review
L [ " NONE_DESC " ] = " Cache tous les messages de cet addon. " -- Needs review
L [ " NOTINCHANNEL " ] = " LibSink : %s (l'envoi vers le canal '%s' a échoué, car vous n'êtes pas dessus) " -- Needs review
L [ " OUTPUT " ] = " Sortie " -- Needs review
L [ " OUTPUT_DESC " ] = " Vers où diriger la sortie de cet addon. " -- Needs review
L [ " ROUTE " ] = " Dirige la sortie de cet addon vers %s " -- Needs review
L [ " SCROLL " ] = " Sous-section " -- Needs review
L [ " SCROLL_DESC " ] = [ = [ Définit la sous - section dans laquelle les messages doivent apparaître .
Disponible uniquement pour certaines sorties . ] = ] -- Needs review
L [ " STICKY " ] = " Épinglé " -- Needs review
L [ " STICKY_DESC " ] = [ = [ Fait apparaître les messages de cet addon comme é pinglés .
Disponible uniquement pour certaines sorties . ] = ] -- Needs review
L [ " UIERROR " ] = " Cadre des erreurs de Blizzard " -- Needs review
elseif l == " deDE " then
L.DEFAULT = " Standard "
L.CHAT = " Chat "
L.NONE = " Nichts "
L.RW = " Schlachtzugswarnung "
L.BLIZZARD = " Schwebender Kampftext "
L.CHANNEL = " Channel "
L.SAY = " Sagen "
L.PARTY = " Gruppe "
L.INSTANCE_CHAT = " Instanz "
L.GUILD_CHAT = " Gildenchat "
L.OFFICER_CHAT = " Offizierchat "
L.YELL = " Schreien "
L.RAID = " Schlachtzug "
L.RAID_WARNING = " Schlachtzugswarnung "
L.GROUP = " Gruppe "
L [ " DEFAULT_DESC " ] = " Die Ausgaben dieses Addons werden durch den ersten verfügbaren Handler geleitet, es werden Schwebender-Kampftext-Addons bevorzugt, wenn diese vorhanden sind. "
L [ " NONE_DESC " ] = " Alle Meldungen dieses Addons verstecken. "
L [ " NOTINCHANNEL " ] = " LibSink : %s (Senden auf Channel \" %s \" gescheitert, da du nicht in ihm bist) "
L [ " OUTPUT " ] = " Ausgabe "
L [ " OUTPUT_DESC " ] = " Wohin die Ausgaben dieses Addons geleitet werden sollen. "
L [ " ROUTE " ] = " Die Ausgaben dieses Addons werden durch %s geleitet. "
L [ " SCROLL " ] = " Unterabschnitt "
L [ " SCROLL_DESC " ] = [ = [ Stelle den Unterabschnitt ein , in dem die Nachrichten erscheinen sollen .
Dies ist nur für manche Ausgaben verfügbar . ] = ]
L [ " STICKY " ] = " Fixiert "
L [ " STICKY_DESC " ] = [ = [ Lässt Nachrichten dieses Addons als fixiert erscheinen , das heißt , dass die Ausgaben an einer festen Position auf dem Bildschirm erscheinen und dort wieder verschwinden .
Dies ist nur für manche Ausgaben verfügbar . ] = ]
L [ " UIERROR " ] = " Blizzards Fehlerfenster "
elseif l == " zhCN " then
L.DEFAULT = " 默认 "
L.CHAT = " 聊天 "
L.NONE = " 无 "
L.RW = " 团队通知 "
L.BLIZZARD = " 浮动战斗信息 "
L.CHANNEL = " 频道 "
L.SAY = " 说 "
L.PARTY = " 小队 "
L.INSTANCE_CHAT = " 副本 "
L.GUILD_CHAT = " 公会聊天 "
L.OFFICER_CHAT = " 官员聊天 "
L.YELL = " 大喊 "
L.RAID = " 团队 "
L.RAID_WARNING = " 团队通知 "
L.GROUP = " 小队 "
L [ " DEFAULT_DESC " ] = " 从这个插件路由输出到第一个可用的处理程序,倾向于可用的滚动战斗文本插件。 "
L [ " NONE_DESC " ] = " 隐藏此插件全部消息。 "
L [ " NOTINCHANNEL " ] = " LibSink:%s(发送到频道“%s”失败,不在此频道) "
L [ " OUTPUT " ] = " 输出 "
L [ " OUTPUT_DESC " ] = " 从此插件路由输出。 "
L [ " ROUTE " ] = " 从此插件通过%s路由输出。 "
L [ " SCROLL " ] = " 子区段 "
L [ " SCROLL_DESC " ] = [ = [ 设 置 子 区 段 消 息 出 现 状 态 。
只 在 一 些 输 出 可 用 。 ] = ]
L [ " STICKY " ] = " 固定 "
L [ " STICKY_DESC " ] = [ = [ 设 置 信 息 从 此 插 件 出 现 状 态 为 固 定 。
只 在 一 些 输 出 可 用 。 ] = ]
L [ " UIERROR " ] = " 暴雪错误框体 "
elseif l == " zhTW " then
L.DEFAULT = " 預設值 "
L.CHAT = " 對話 "
L.NONE = " 無 "
L.RW = " 團隊警告 "
L.BLIZZARD = " 浮動戰鬥文字 "
L.CHANNEL = " 頻道 "
L.SAY = " 說 "
L.PARTY = " 隊伍 "
L.INSTANCE_CHAT = " 副本 "
L.GUILD_CHAT = " 公會對話 "
L.OFFICER_CHAT = " 幹部對話 "
L.YELL = " 大喊 "
L.RAID = " 團隊 "
L.RAID_WARNING = " 團隊警告 "
L.GROUP = " 小隊 "
L [ " DEFAULT_DESC " ] = " 從這個插件路由輸出到第一個可用的處理程式,傾向於可用的滾動戰鬥文本插件。 "
L [ " NONE_DESC " ] = " 隱藏此插件全部訊息。 "
L [ " NOTINCHANNEL " ] = " LibSink:%s(發送到頻道“%s”失敗,不在此頻道) "
L [ " OUTPUT " ] = " 輸出 "
L [ " OUTPUT_DESC " ] = " 從此插件路由輸出。 "
L [ " ROUTE " ] = " 從此插件通過%s路由輸出。 "
L [ " SCROLL " ] = " 子區段 "
L [ " SCROLL_DESC " ] = [ = [ 設 置 子 區 段 訊 息 出 現 狀 態 。
只 在 一 些 輸 出 可 用 。 ] = ]
L [ " STICKY " ] = " 固定 "
L [ " STICKY_DESC " ] = [ = [ 設 置 訊 息 從 此 插 件 出 現 狀 態 為 固 定 。
只 在 一 些 輸 出 可 用 。 ] = ]
L [ " UIERROR " ] = " 暴雪錯誤框體 "
elseif l == " ruRU " then
L.DEFAULT = " По умолчанию "
L.CHAT = " Каналы "
L.NONE = " Нет "
L.RW = " Объявление рейду "
L.BLIZZARD = " Текст боя "
L.CHANNEL = " Канал "
L.SAY = " Речь "
L.PARTY = " Группа "
L.INSTANCE_CHAT = " Подземелье "
L.GUILD_CHAT = " Канал гильдии "
L.OFFICER_CHAT = " Канал офицеров "
L.YELL = " Крик "
L.RAID = " Рейд "
L.RAID_WARNING = " Объявление рейду "
L.GROUP = " Группа "
L [ " DEFAULT_DESC " ] = " Направлять вывод из этого аддона через первый доступный обработчик, предпочитая аддоны прокрутки журнала боя если они доступны. "
L [ " NONE_DESC " ] = " Скрыть все сообщения этого аддона "
L [ " NOTINCHANNEL " ] = " LibSink: %s (Отправка в канал '%s' неудачна, вы не в нем) "
L [ " OUTPUT " ] = " Вывод "
L [ " OUTPUT_DESC " ] = " Куда направлять вывод из этого аддона. "
L [ " ROUTE " ] = " Направлять вывод из этого аддона через %s. "
L [ " SCROLL " ] = " Подразделы "
L [ " SCROLL_DESC " ] = [ = [ У с т а н о в и т ь п о д р а з д е л , г д е д о л ж н ы п о я в л я т ь с я с о о б щ е н и я .
Д о с т у п н о т о л ь к о д л я н е к о т о р ы х в ы в о д о в . ] = ]
L [ " STICKY " ] = " Прикрепление "
L [ " STICKY_DESC " ] = [ = [ П р и к р е п л я т ь с о о б щ е н и я и з э т о г о а д д о н а
Д о с т у п н о т о л ь к о д л я н е к о т о р ы х в ы в о д о в . ] = ]
L [ " UIERROR " ] = " Фрейм ошибок Blizzard. "
elseif l == " esES " or l == " esMX " then
L.DEFAULT = " Predeterminado "
L.CHAT = " Chat "
L.NONE = " Ninguno "
L.RW = " Aviso de la banda "
L.BLIZZARD = " Texto flotante de combate "
L.CHANNEL = " Canal "
L.SAY = " Hablar "
L.PARTY = " Grupo "
L.INSTANCE_CHAT = " Estancia "
L.GUILD_CHAT = " Chat de hermandad "
L.OFFICER_CHAT = " Chat de oficiales "
L.YELL = " Gritar "
L.RAID = " Banda "
L.RAID_WARNING = " Aviso de la banda "
L.GROUP = " Grupo "
L [ " DEFAULT_DESC " ] = " Ruta de salida de este addon mediante el primer controlador disponible, prefiriendo el desplazamiento de texto de combate si está disponible. " -- Needs review
L [ " NONE_DESC " ] = " Oculta todos los mensajes de este addon. " -- Needs review
L [ " NOTINCHANNEL " ] = " LibSink: %s (Falló al enviar al canal '%s', no estás en el) " -- Needs review
L [ " OUTPUT " ] = " Salida " -- Needs review
L [ " OUTPUT_DESC " ] = " Donde se ajustará la ruta de salida de este addon. " -- Needs review
L [ " ROUTE " ] = " Ruta de salida de este addon mediante %s. " -- Needs review
L [ " SCROLL " ] = " Sub sección. " -- Needs review
L [ " SCROLL_DESC " ] = [ = [ Ajusta la sub sección donde los mensajes deben aparecer .
Disponible sólo para algunas salidas . ] = ] -- Needs review
L [ " STICKY " ] = " Chincheta " -- Needs review
L [ " STICKY_DESC " ] = [ = [ Ajusta los mensajes de este addon para que aparezcan como chincheta .
Disponible sólo para algunas salidas . ] = ] -- Needs review
L [ " UIERROR " ] = " Marco de Errores de Blizzard " -- Needs review
elseif l == " ptBR " then
L.DEFAULT = " Padrão "
L.CHAT = " Bate-papo "
L.NONE = " Nenhum "
L.RW = " Aviso do raide "
L.BLIZZARD = " Texto de combate "
L.CHANNEL = " Canal "
L.SAY = " Dizer "
L.PARTY = " Grupo "
L.INSTANCE_CHAT = " Instância "
L.GUILD_CHAT = " Bate-papo da guilda "
L.OFFICER_CHAT = " Bate-papo de oficiais "
L.YELL = " Gritar "
L.RAID = " Raide "
L.RAID_WARNING = " Aviso do raide "
L.GROUP = " Grupo "
--L.DEFAULT_DESC = "Route output from this addon through the first available handler, preferring scrolling combat text addons if available."
--L.ROUTE = "Route output from this addon through %s."
--L.UIERROR = "Blizzard Error Frame"
--L.OUTPUT = "Output"
--L.OUTPUT_DESC = "Where to route the output from this addon."
--L.SCROLL = "Sub section"
--L.SCROLL_DESC = "Set the sub section where messages should appear.\n\nOnly available for some outputs."
--L.STICKY = "Sticky"
--L.STICKY_DESC = "Set messages from this addon to appear as sticky.\n\nOnly available for some outputs."
--L.NONE_DESC = "Hide all messages from this addon."
--L.NOTINCHANNEL = "LibSink: %s (Sending to channel '%s' failed, you're not in it)"
elseif l == " itIT " then
L.DEFAULT = " Predefinito "
L.CHAT = " Chat "
L.NONE = " Nessuno "
L.RW = " Avviso incursione "
L.BLIZZARD = " Testo di combattimento "
L.CHANNEL = " Canale "
L.SAY = " Parla "
L.PARTY = " Gruppo "
L.INSTANCE_CHAT = " Istanza "
L.GUILD_CHAT = " Chat di gilda "
L.OFFICER_CHAT = " Chat degli ufficiali "
L.YELL = " Urla "
L.RAID = " Incursione "
L.RAID_WARNING = " Avviso incursione "
L.GROUP = " Gruppo "
L [ " DEFAULT_DESC " ] = " Indirizza l'uscita da questo addon attraverso il primo metodo di uscita disponibile, preferibilmente un addon visivo a schermo se disponibile. "
L [ " NONE_DESC " ] = " Nasconti tutti i messaggi per questo addon. "
L [ " NOTINCHANNEL " ] = " LibSink: %s (Invio al canale '%s' non riuscito, non sei dentro) "
L [ " OUTPUT " ] = " Uscita "
L [ " OUTPUT_DESC " ] = " Dove indirizzare l'uscita da questo addon. "
L [ " ROUTE " ] = " Indirizza l'uscita da questo addon attraverso %s. "
L [ " SCROLL " ] = " Sotto sezione "
L [ " SCROLL_DESC " ] = [ = [ Imposta la sotto sezione in cui i messaggi devono apparire .
Disponibile solo per alcune uscite . ] = ]
L [ " STICKY " ] = " Importante "
L [ " STICKY_DESC " ] = [ = [ Imposta i messaggi di questo addon di apparire come importanti .
Disponibile solo per alcune uscite . ] = ]
L [ " UIERROR " ] = " Frame Errore Blizzard "
end
end
local SML = LibStub ( " LibSharedMedia-3.0 " , true )
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 = sink.storageForAddon [ addon ] and sink.storageForAddon [ addon ] . sink20Sticky 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 = sink.storageForAddon [ addon ] and sink.storageForAddon [ addon ] . sink20Sticky 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 = " \124 T " .. icon .. " :15:15:0:0:64:64:4:60:4:60 \124 t " .. text end
local s = sink.storageForAddon [ addon ] and sink.storageForAddon [ addon ] . sink20Sticky or sticky
if loadFCT then loadFCT ( ) end
CombatText_AddMessage ( text , CombatText_StandardScroll , r , g , b , s and " crit " or nil , false )
end
sink.channelMapping = sink.channelMapping or {
[ L.SAY ] = " SAY " ,
[ L.PARTY ] = " PARTY " ,
[ L.INSTANCE_CHAT ] = " INSTANCE_CHAT " ,
[ L.GUILD_CHAT ] = " GUILD " ,
[ L.OFFICER_CHAT ] = " OFFICER " ,
[ L.YELL ] = " YELL " ,
[ L.RAID ] = " RAID " ,
[ L.RAID_WARNING ] = " RAID_WARNING " ,
[ L.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 ( " # " , ... ) , 3 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 & icons
text = gsub ( text , " (|c%x%x%x%x%x%x%x%x)(.-)(|r) " , color_strip )
text = gsub ( text , " |T.-|t " , " " )
local loc = sink.storageForAddon [ addon ] and sink.storageForAddon [ addon ] . sink20ScrollArea
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 ( format ( L.NOTINCHANNEL , text , loc ) )
end
return
end
SendChatMessage ( text , chan or " SAY " )
end
-- |TTexturePath:size1:size2:xoffset:yoffset:dimx:dimy:coordx1:coordx2:coordy1:coordy2:red:green:blue|t
local function chat ( _ , text , r , g , b , _ , _ , _ , _ , _ , icon )
if icon then text = " \124 T " .. icon .. " :15:15:0:0:64:64:4:60:4:60 \124 t " .. text end
DEFAULT_CHAT_FRAME : AddMessage ( text , r , g , b )
end
local function uierror ( _ , text , r , g , b , _ , _ , _ , _ , _ , icon )
if icon then text = " \124 T " .. icon .. " :15:15:0:0:64:64:4:60:4:60 \124 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 ( _ , text , r , g , b , _ , _ , _ , _ , _ , icon )
if r or g or b then
text = format ( " \124 cff%02x%02x%02x%s \124 r " , ( r or 0 ) * 255 , ( g or 0 ) * 255 , ( b or 0 ) * 255 , text )
end
if icon then text = " \124 T " .. icon .. " :15:15:0:0:64:64:4:60:4:60 \124 t " .. text end
RaidNotice_AddMessage ( RaidWarningFrame , text , white )
end
end
local function noop ( ) --[[ noop! ]] end
local handlerPriority = { " SCT " , " MikSBT " }
local customHandlersEnabled = {
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 = 1 , # handlerPriority do
local handler = handlerPriority [ i ]
local check = customHandlersEnabled [ handler ]
if check and check ( ) then
currentHandler = handler
return sink.handlers [ handler ]
end
end
return blizzard
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 sctFrames = { " Incoming " , " Outgoing " , " Messages " }
local msbtFrames = nil
local function getScrollAreasForAddon ( addon )
if type ( addon ) ~= " string " then return nil end
if addon == " MikSBT " then
if not msbtFrames then
msbtFrames = { }
for _ , name in MikSBT.IterateScrollAreas ( ) do
msbtFrames [ # msbtFrames + 1 ] = name
end
end
return msbtFrames
elseif addon == " SCT " then
return sctFrames
elseif addon == " Channel " then
local 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 = { " Scrolling Combat Text (SCT) " , nil , shouldDisableSCT } ,
MikSBT = { " MikSBT " , nil , shouldDisableMSBT } ,
Blizzard = { L.BLIZZARD } ,
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
local tbl = { }
for i = 1 , # sa do
local n = sa [ i ]
tbl [ n ] = n
end
options [ " Ace3 " ] [ addon ] . args.ScrollArea . values = tbl
options [ " Ace3 " ] [ addon ] . args.ScrollArea . disabled = nil
else
options [ " Ace3 " ] [ addon ] . args.ScrollArea . disabled = true
options [ " Ace3 " ] [ addon ] . args.ScrollArea . values = emptyTable
end
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
local tbl = { }
for i = 1 , # sa do
local n = sa [ i ]
tbl [ n ] = n
end
options [ " Ace3 " ] [ addon ] . args.ScrollArea . values = tbl
options [ " Ace3 " ] [ addon ] . args.ScrollArea . disabled = nil
else
options [ " Ace3 " ] [ addon ] . args.ScrollArea . disabled = true
options [ " Ace3 " ] [ addon ] . args.ScrollArea . values = emptyTable
end
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 type ( scrollAreaFunc ) == " string " or scrollAreaFunc == nil )
assert ( type ( hasSticky ) == " boolean " or hasSticky == nil )
if sinks [ shortName ] or sink.handlers [ shortName ] then
error ( format ( " 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 _ , 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 = {
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